<!DOCTYPE html>


  <html class="dark page-post">


<head><meta name="generator" content="Hexo 3.9.0">
  <meta charset="utf-8">
  
  <title>Typescript总结篇（二） | Poetry&#39;s Blog</title>

  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  
    <meta name="keywords" content="Javascript,Typescript,">
  

  <meta name="description" content="一、简介1.1 什么是 TypeScript TypeScript 是 JavaScript 的一个超集，主要提供了类型系统和对 ES6的支持 TypeScript 是由微软开发的一款开源的编程语言 TypeScript 是 Javascript 的超级，遵循最新的 ES6、Es5 规范。TypeScript 扩展了 JavaScript 的语法 TypeScript 更像后端 java、C#这样">
<meta name="keywords" content="Javascript,Typescript">
<meta property="og:type" content="article">
<meta property="og:title" content="Typescript总结篇（二）">
<meta property="og:url" content="http://blog.poetries.top/2018/12/30/ts-summary/index.html">
<meta property="og:site_name" content="Poetry&#39;s Blog">
<meta property="og:description" content="一、简介1.1 什么是 TypeScript TypeScript 是 JavaScript 的一个超集，主要提供了类型系统和对 ES6的支持 TypeScript 是由微软开发的一款开源的编程语言 TypeScript 是 Javascript 的超级，遵循最新的 ES6、Es5 规范。TypeScript 扩展了 JavaScript 的语法 TypeScript 更像后端 java、C#这样">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/2019/10/583.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/2019/10/584.png">
<meta property="og:image" content="https://poetries1.gitee.io/img-repo/2019/10/585.png">
<meta property="og:updated_time" content="2020-08-15T04:25:31.938Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Typescript总结篇（二）">
<meta name="twitter:description" content="一、简介1.1 什么是 TypeScript TypeScript 是 JavaScript 的一个超集，主要提供了类型系统和对 ES6的支持 TypeScript 是由微软开发的一款开源的编程语言 TypeScript 是 Javascript 的超级，遵循最新的 ES6、Es5 规范。TypeScript 扩展了 JavaScript 的语法 TypeScript 更像后端 java、C#这样">
<meta name="twitter:image" content="https://poetries1.gitee.io/img-repo/2019/10/583.png">

  

  
    <link rel="icon" href="/favicon.ico">
  

  <link href="/css/styles.css?v=c114cbeddx" rel="stylesheet">
<link href="/css/other.css?v=c114cbeddx" rel="stylesheet">


  
    <link rel="stylesheet" href="/css/personal-style.css">
  

  

  
  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "//hm.baidu.com/hm.js?40b1f89aa80f2527b3db779c6898c879";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>


  
  <script type="text/javascript">
	(function(){
	    var bp = document.createElement('script');
	    var curProtocol = window.location.protocol.split(':')[0];
	    if (curProtocol === 'https') {
	        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';        
	    }
	    else {
	        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
	    }
	    var s = document.getElementsByTagName("script")[0];
	    s.parentNode.insertBefore(bp, s);
	})();
  </script>



  
    <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <link rel="stylesheet" href="//cdn.bootcss.com/font-awesome/4.3.0/css/font-awesome.min.css">
  

  <!-- 聊天系统 -->
  
    
   <link type="text/css" rel="stylesheet" href="/renxi/default.css">
   <style>
      #modal {
        position: static !important;
      }
      .filter {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        background: #fe5757;
        animation: colorChange 30s ease-in-out infinite;
        animation-fill-mode: both;
        mix-blend-mode: overlay;
      }
  
      @keyframes colorChange {
        0%, 100% {
            opacity: 0;
        }
        50% {
            opacity: .9;
        }
      }
   </style>
</head>
</html>
<body>
  
  
    <span id="toolbox-mobile" class="toolbox-mobile">导航</span>
  

  <div class="post-header CENTER">
   
  <div class="toolbox">
    <a class="toolbox-entry" href="/">
      <span class="toolbox-entry-text">导航</span>
      <i class="icon-angle-down"></i>
      <i class="icon-home"></i>
    </a>
    <ul class="list-toolbox">
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/archives/"
            rel="noopener noreferrer"
            target="_self"
            >
            博客
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/categories/"
            rel="noopener noreferrer"
            target="_self"
            >
            分类
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/tags/"
            rel="noopener noreferrer"
            target="_self"
            >
            标签
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/search/"
            rel="noopener noreferrer"
            target="_self"
            >
            搜索
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/link/"
            rel="noopener noreferrer"
            target="_self"
            >
            友链
          </a>
        </li>
      
        <li class="item-toolbox">
          <a
            class="CIRCLE"
            href="/about/"
            rel="noopener noreferrer"
            target="_self"
            >
            关于
          </a>
        </li>
      
    </ul>
  </div>


</div>


  <div id="toc" class="toc-article">
    <strong class="toc-title">文章目录<i class="iconfont toc-title" style="display:inline-block;color:#87998d;width:20px;height:20px;">&#xf004b;</i></strong>
    <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#一、简介"><span class="toc-text">一、简介</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-1-什么是-TypeScript"><span class="toc-text">1.1 什么是 TypeScript</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-2-为什么选择-TypeScript"><span class="toc-text">1.2 为什么选择 TypeScript</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-3-安装-TypeScript"><span class="toc-text">1.3 安装 TypeScript</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-4-Hello-TypeScript"><span class="toc-text">1.4 Hello TypeScript</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#二、基础"><span class="toc-text">二、基础</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#2-1-原始数据类型"><span class="toc-text">2.1 原始数据类型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-1-布尔值"><span class="toc-text">2.1.1 布尔值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-2-数值"><span class="toc-text">2.1.2 数值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-3-字符串"><span class="toc-text">2.1.3 字符串</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-4-空值"><span class="toc-text">2.1.4 空值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-5-Null-和-Undefined"><span class="toc-text">2.1.5 Null 和 Undefined</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-2-任意值Any"><span class="toc-text">2.2 任意值Any</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-3-类型推论"><span class="toc-text">2.3 类型推论</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-4-联合类型"><span class="toc-text">2.4 联合类型</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-5-对象的类型——接口"><span class="toc-text">2.5 对象的类型——接口</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-1-简单例子"><span class="toc-text">2.5.1 简单例子</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-2-可选属性"><span class="toc-text">2.5.2 可选属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-3-任意属性"><span class="toc-text">2.5.3 任意属性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-4-只读属性"><span class="toc-text">2.5.4 只读属性</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-6-数组的类型"><span class="toc-text">2.6 数组的类型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-6-1「类型-方括号」表示法"><span class="toc-text">2.6.1「类型 + 方括号」表示法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-6-2-数组泛型"><span class="toc-text">2.6.2 数组泛型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-6-3-用接口表示数组"><span class="toc-text">2.6.3 用接口表示数组</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-6-4-any-在数组中的应用"><span class="toc-text">2.6.4 any 在数组中的应用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-6-5-类数组"><span class="toc-text">2.6.5 类数组</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-7-函数的类型"><span class="toc-text">2.7 函数的类型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-7-1-函数声明"><span class="toc-text">2.7.1 函数声明</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-7-2-函数表达式"><span class="toc-text">2.7.2 函数表达式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-7-3-用接口定义函数的形状"><span class="toc-text">2.7.3 用接口定义函数的形状</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-7-4-参数默认值"><span class="toc-text">2.7.4 参数默认值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-7-5-剩余参数"><span class="toc-text">2.7.5 剩余参数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-7-6-函数重载"><span class="toc-text">2.7.6 函数重载</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-8-类型断言"><span class="toc-text">2.8 类型断言</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-9-声明文件"><span class="toc-text">2.9 声明文件</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-9-1-声明-declare-语句"><span class="toc-text">2.9.1 声明(declare)语句</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-9-2-声明文件-约定-d-ts后缀"><span class="toc-text">2.9.2 声明文件(约定.d.ts后缀)</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-9-3-第三方声明文件"><span class="toc-text">2.9.3 第三方声明文件</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-10-内置对象"><span class="toc-text">2.10 内置对象</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-10-1-ECMAScript-的内置对象"><span class="toc-text">2.10.1 ECMAScript 的内置对象</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-10-2-DOM-和-BOM-的内置对象"><span class="toc-text">2.10.2 DOM 和 BOM 的内置对象</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-10-3-TypeScript-核心库的定义文件"><span class="toc-text">2.10.3 TypeScript 核心库的定义文件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-10-4-用-TypeScript-写-Node-js"><span class="toc-text">2.10.4 用 TypeScript 写 Node.js</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#三、进阶"><span class="toc-text">三、进阶</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#3-1-类型别名"><span class="toc-text">3.1 类型别名</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-2-字符串字面量类型"><span class="toc-text">3.2 字符串字面量类型</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-3-元组"><span class="toc-text">3.3 元组</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-1-简单的例子"><span class="toc-text">3.3.1 简单的例子</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-2-越界的元素"><span class="toc-text">3.3.2 越界的元素</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-4-枚举"><span class="toc-text">3.4 枚举</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4-1-简单的例子"><span class="toc-text">3.4.1 简单的例子</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4-2-手动赋值"><span class="toc-text">3.4.2 手动赋值</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4-3-常数项和计算所得项"><span class="toc-text">3.4.3 常数项和计算所得项</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4-4-常数枚举"><span class="toc-text">3.4.4 常数枚举</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4-5-外部枚举"><span class="toc-text">3.4.5 外部枚举</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-5-类"><span class="toc-text">3.5 类</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-1-类的概念"><span class="toc-text">3.5.1 类的概念</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-2-public-private-和-protected"><span class="toc-text">3.5.2 public private 和 protected</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-3-抽象类"><span class="toc-text">3.5.3 抽象类</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-4-类的类型"><span class="toc-text">3.5.4 类的类型</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-6-类与接口"><span class="toc-text">3.6 类与接口</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-6-1-类实现接口"><span class="toc-text">3.6.1 类实现接口</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-6-2-接口继承接口"><span class="toc-text">3.6.2 接口继承接口</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-6-3-接口继承类"><span class="toc-text">3.6.3 接口继承类</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-6-4-混合类型"><span class="toc-text">3.6.4 混合类型</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-7-泛型"><span class="toc-text">3.7 泛型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-7-1-简单的例子"><span class="toc-text">3.7.1 简单的例子</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-7-2-多个类型参数"><span class="toc-text">3.7.2 多个类型参数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-7-3-泛型约束"><span class="toc-text">3.7.3 泛型约束</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-7-4-泛型接口"><span class="toc-text">3.7.4 泛型接口</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-7-5-泛型类"><span class="toc-text">3.7.5 泛型类</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-7-6-泛型参数的默认类型"><span class="toc-text">3.7.6 泛型参数的默认类型</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-8-声明合并"><span class="toc-text">3.8 声明合并</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-8-1-函数的合并"><span class="toc-text">3.8.1 函数的合并</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-8-2-接口的合并"><span class="toc-text">3.8.2 接口的合并</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-8-3-类的合并"><span class="toc-text">3.8.3 类的合并</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#四、工程"><span class="toc-text">四、工程</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#4-1-tsconfig-json"><span class="toc-text">4.1 tsconfig.json</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-2-TypeScript-编译"><span class="toc-text">4.2 TypeScript 编译</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#五、一些例子演示"><span class="toc-text">五、一些例子演示</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#5-1-定义ajax请求数据接口"><span class="toc-text">5.1 定义ajax请求数据接口</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-2-函数类型接口-对方法约束"><span class="toc-text">5.2 函数类型接口-对方法约束</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-3-可索引接口：数组、对象的约束（不常用）"><span class="toc-text">5.3 可索引接口：数组、对象的约束（不常用）</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#5-3-1-可索引接口-对数组的约束"><span class="toc-text">5.3.1 可索引接口-对数组的约束</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-3-2-可索引接口-对对象的约束"><span class="toc-text">5.3.2 可索引接口-对对象的约束</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-3-3-类类型接口-对类的约束"><span class="toc-text">5.3.3 类类型接口:对类的约束</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-4-接口的扩展"><span class="toc-text">5.4 接口的扩展</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-5-泛型类接口"><span class="toc-text">5.5 泛型类接口</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#5-5-1-泛型类-泛型方法"><span class="toc-text">5.5.1 泛型类 泛型方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-5-2-泛型接口"><span class="toc-text">5.5.2 泛型接口</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#六、更多参考"><span class="toc-text">六、更多参考</span></a></li></ol>
  </div>
  




<div class="content content-post CENTER">
   <!-- canvas 彩带 -->
<canvas id="evanyou" width="1302" height="678" style="position: fixed;width: 100%;height: 100%;top: 0;left:0;z-index:-1;"></canvas>

<article id="post-ts-summary" class="article article-type-post" itemprop="blogPost">
  <header class="article-header" style="position:relative;">
    <h1 class="post-title">Typescript总结篇（二）</h1>

    <div class="article-meta">
      <span>
        <i class="icon-calendar"></i>
        <span>2018.12.30</span>
      </span>

      
        <span class="article-author">
          <i class="icon-user"></i>
          <span>Poetry</span>
        </span>
      

      
  <span class="article-category">
    <i class="icon-list"></i>
    <a class="article-category-link" href="/categories/Front-End/">Front-End</a>
  </span>



      

      
      <i class="fa fa-eye"></i> 
        <span id="busuanzi_container_page_pv">
           &nbsp热度 <span id="busuanzi_value_page_pv">
           <i class="fa fa-spinner fa-spin"></i></span>℃
        </span>
      
      
       
          <span class="post-count">
            <i class="fa fa-file-word-o"></i>&nbsp
            <span>字数统计 14k字</span>
          </span>

          <span class="post-count">
            <i class="fa fa-columns"></i>&nbsp
            <span>阅读时长 62分</span>
          </span>
      
      
    </div>

    <i class="iconfont" id="toc-eye" style="display:inline-block;color:#b36619;position:absolute;top:0;right:0;cursor:pointer;
    font-size: 24px;">&#xe61c;</i>

  </header>

  <div class="article-content">
    
      <div id="container">
        <h1 id="一、简介"><a href="#一、简介" class="headerlink" title="一、简介"></a>一、简介</h1><h2 id="1-1-什么是-TypeScript"><a href="#1-1-什么是-TypeScript" class="headerlink" title="1.1 什么是 TypeScript"></a>1.1 什么是 TypeScript</h2><ul>
<li><code>TypeScript</code> 是 <code>JavaScript</code> 的一个超集，主要提供了类型系统和对 <code>ES6</code>的支持</li>
<li><code>TypeScript</code> 是由微软开发的一款开源的编程语言</li>
<li><code>TypeScript</code> 是 <code>Javascript</code> 的超级，遵循最新的 <code>ES6</code>、<code>Es5</code> 规范。<code>TypeScript</code> 扩展了 <code>JavaScript</code> 的语法</li>
<li><code>TypeScript</code> 更像后端 <code>java</code>、<code>C#</code>这样的面向对象语言可以让 <code>js</code> 开发大型企业项目</li>
</ul>
<h2 id="1-2-为什么选择-TypeScript"><a href="#1-2-为什么选择-TypeScript" class="headerlink" title="1.2 为什么选择 TypeScript"></a>1.2 为什么选择 TypeScript</h2><blockquote>
<p><code>Typescript</code>和<code>es6</code>、<code>es5</code>关系</p>
</blockquote>
<p><img src="https://poetries1.gitee.io/img-repo/2019/10/583.png" alt></p>
<p><strong>TypeScript 增加了代码的可读性和可维护性</strong></p>
<ul>
<li>类型系统实际上是最好的文档，大部分的函数看看类型的定义就可以知道如何使用了</li>
<li>可以在编译阶段就发现大部分错误，这总比在运行时候出错好</li>
<li>增强了编辑器和 <code>IDE</code> 的功能，包括代码补全、接口提示、跳转到定义、重构等</li>
</ul>
<p><strong>TypeScript 非常包容</strong></p>
<ul>
<li><code>TypeScript</code> 是 <code>JavaScript</code> 的超集，<code>.js</code> 文件可以直接重命名为 <code>.ts</code> 即可</li>
<li>即使不显式的定义类型，也能够自动做出类型推论</li>
<li>可以定义从简单到复杂的几乎一切类型</li>
<li>即使 <code>TypeScript</code> 编译报错，也可以生成 <code>JavaScript</code> 文件</li>
<li>兼容第三方库，即使第三方库不是用 <code>TypeScript</code> 写的，也可以编写单独的类型文件供 <code>TypeScript</code> 读取</li>
</ul>
<p><strong>TypeScript 拥有活跃的社区</strong></p>
<ul>
<li>大部分第三方库都有提供给 <code>TypeScript</code> 的类型定义文件</li>
<li><code>Google</code> 开发的<code>Angular2</code> 就是使用 <code>TypeScript</code> 编写的</li>
<li><code>TypeScript</code> 拥抱了 <code>ES6</code> 规范，也支持部分 <code>ESNext</code> 草案的规范</li>
<li>最新的 <code>Vue</code> 、<code>React</code> 也可以集成 <code>TypeScript</code></li>
</ul>
<p><strong>TypeScript 的缺点</strong></p>
<ul>
<li>有一定的学习成本，需要理解接口（<code>Interfaces</code>）、泛型（<code>Generics</code>）、类（<code>Classes</code>）、枚举类型（<code>Enums</code>）等前端工程师可能不是很熟悉的概念</li>
<li>短期可能会增加一些开发成本，毕竟要多写一些类型的定义，不过对于一个需要长期维护的项目，<code>TypeScript</code> 能够减少其维护成本</li>
<li>集成到构建流程需要一些工作量</li>
<li>可能和一些库结合的不是很完美</li>
</ul>
<h2 id="1-3-安装-TypeScript"><a href="#1-3-安装-TypeScript" class="headerlink" title="1.3 安装 TypeScript"></a>1.3 安装 TypeScript</h2><p><strong>typescript 安装</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">npm i typescript -g</span><br></pre></td></tr></table></figure>
<blockquote>
<p>全局安装完成后，我们新建一个<code>hello.ts</code>的<code>ts</code>文件</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// hello.ts内容</span></span><br><span class="line"><span class="keyword">let</span> a = <span class="string">"poet"</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>接下来我们在命令行输入<code>tsc hello.ts</code>来编译这个<code>ts</code>文件，然后会在同级目录生成一个编译好了的<code>hello.js</code>文件</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// hello.js内容</span></span><br><span class="line"><span class="keyword">var</span> = <span class="string">"poet"</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>那么我们每次都要输<code>tsc hello.ts</code>命令来编译，这样很麻烦，能否让它自动编译？答案是可以的，使用<code>vscode</code>来开发，需要配置一下<code>vscode</code>就可以。</p>
</blockquote>
<blockquote>
<p>首先我们在命令行执行<code>tsc --init</code>来生成配置文件，然后我们在目录下看到生成了一个<code>tsconfig.json</code>文件</p>
</blockquote>
<p><img src="https://poetries1.gitee.io/img-repo/2019/10/584.png" alt></p>
<blockquote>
<p>这个<code>json</code>文件里有很多选项</p>
</blockquote>
<ul>
<li><code>target</code>是选择编译到什么语法</li>
<li><code>module</code>则是模块类型</li>
<li><code>outDir</code>则是输出目录，可以指定这个参数到指定目录</li>
</ul>
<blockquote>
<p>更多细节 <a href="https://zhongsp.gitbooks.io/typescript-handbook/content/doc/handbook/tsconfig.json.html" target="_blank" rel="noopener">https://zhongsp.gitbooks.io/typescript-handbook/content/doc/handbook/tsconfig.json.html</a></p>
</blockquote>
<blockquote>
<p>接下来我们需要开启监控了，在<code>vscode</code>任务栏中</p>
</blockquote>
<p><img src="https://poetries1.gitee.io/img-repo/2019/10/585.png" alt></p>
<h2 id="1-4-Hello-TypeScript"><a href="#1-4-Hello-TypeScript" class="headerlink" title="1.4 Hello TypeScript"></a>1.4 Hello TypeScript</h2><blockquote>
<p>将以下代码复制到 <code>hello.ts</code> 中</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sayHello</span>(<span class="params">person: string</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">'Hello, '</span> + person;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> user = <span class="string">'poetries'</span>;</span><br><span class="line"><span class="built_in">console</span>.log(sayHello(user));</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">tsc hello.ts</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//这时候会生成一个编译好的文件 hello.js：</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sayHello</span>(<span class="params">person</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">'Hello, '</span> + person;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> user = <span class="string">'poetries'</span>;</span><br><span class="line"><span class="built_in">console</span>.log(sayHello(user));</span><br></pre></td></tr></table></figure>
<blockquote>
<p><code>TypeScript</code> 中，使用 <code>:</code> 指定变量的类型，<code>:</code> 的前后有没有空格都可以</p>
</blockquote>
<ul>
<li><code>TypeScript</code> 只会进行静态检查，如果发现有错误，编译的时候就会报错</li>
<li><code>TypeScript</code> 编译的时候即使报错了，还是会生成编译结果，我们仍然可以使用这个编译之后的文件</li>
</ul>
<h1 id="二、基础"><a href="#二、基础" class="headerlink" title="二、基础"></a>二、基础</h1><h2 id="2-1-原始数据类型"><a href="#2-1-原始数据类型" class="headerlink" title="2.1 原始数据类型"></a>2.1 原始数据类型</h2><blockquote>
<p><code>JavaScript</code> 的类型分为两种：原始数据类型（<code>Primitive data types</code>）和对象类型（<code>Object types</code>）。</p>
</blockquote>
<ul>
<li>原始数据类型包括：<code>布尔值</code>、<code>数值</code>、<code>字符串</code>、<code>null</code>、<code>undefined</code> 以及 <code>ES6</code>中的新类型 <code>Symbol</code>。</li>
</ul>
<blockquote>
<p>本节主要介绍前五种原始数据类型在 <code>TypeScript</code> 中的应用</p>
</blockquote>
<h3 id="2-1-1-布尔值"><a href="#2-1-1-布尔值" class="headerlink" title="2.1.1 布尔值"></a>2.1.1 布尔值</h3><blockquote>
<p>布尔值是最基础的数据类型，在 <code>TypeScript</code> 中，使用 <code>boolean</code> 定义布尔值类型</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> isDone: boolean = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 编译通过</span></span><br><span class="line"><span class="comment">// 后面约定，未强调编译错误的代码片段，默认为编译通过</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>注意，使用构造函数 <code>Boolean</code> 创造的对象不是布尔值</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> createdByNewBoolean: boolean = <span class="keyword">new</span> <span class="built_in">Boolean</span>(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(1,5): error TS2322: Type 'Boolean' is not assignable to type 'boolean'.</span></span><br><span class="line"><span class="comment">// 后面约定，注释中标出了编译报错的代码片段，表示编译未通过</span></span><br></pre></td></tr></table></figure>
<ul>
<li>事实上 <code>new Boolean()</code> 返回的是一个 <code>Boolean</code> 对象：</li>
</ul>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">let createdByNewBoolean: Boolean = new Boolean(1);</span><br></pre></td></tr></table></figure>
<ul>
<li>直接调用 <code>Boolean</code> 也可以返回一个 <code>boolean</code> 类型：</li>
</ul>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">let createdByBoolean: boolean = Boolean(1);</span><br></pre></td></tr></table></figure>
<ul>
<li>在 <code>TypeScript</code> 中，<code>boolean</code>是 <code>JavaScript</code> 中的基本类型，而 <code>Boolean</code> 是 <code>JavaScript</code>中的构造函数。其他基本类型（除了 <code>null</code> 和 <code>undefined</code>）一样</li>
</ul>
<h3 id="2-1-2-数值"><a href="#2-1-2-数值" class="headerlink" title="2.1.2 数值"></a>2.1.2 数值</h3><blockquote>
<p>使用 <code>number</code> 定义数值类型</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> decLiteral: number = <span class="number">6</span>;</span><br><span class="line"><span class="keyword">let</span> hexLiteral: number = <span class="number">0xf00d</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ES6 中的二进制表示法</span></span><br><span class="line"><span class="keyword">let</span> binaryLiteral: number = <span class="number">0b1010</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ES6 中的八进制表示法</span></span><br><span class="line"><span class="keyword">let</span> octalLiteral: number = <span class="number">0o744</span>;</span><br><span class="line"><span class="keyword">let</span> notANumber: number = <span class="literal">NaN</span>;</span><br><span class="line"><span class="keyword">let</span> infinityNumber: number = <span class="literal">Infinity</span>;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//编译结果：</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> decLiteral = <span class="number">6</span>;</span><br><span class="line"><span class="keyword">var</span> hexLiteral = <span class="number">0xf00d</span>;</span><br><span class="line"><span class="comment">// ES6 中的二进制表示法</span></span><br><span class="line"><span class="keyword">var</span> binaryLiteral = <span class="number">10</span>;</span><br><span class="line"><span class="comment">// ES6 中的八进制表示法</span></span><br><span class="line"><span class="keyword">var</span> octalLiteral = <span class="number">484</span>;</span><br><span class="line"><span class="keyword">var</span> notANumber = <span class="literal">NaN</span>;</span><br><span class="line"><span class="keyword">var</span> infinityNumber = <span class="literal">Infinity</span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>其中 <code>0b101</code>0 和 <code>0o744</code>是 <code>ES6</code> 中的二进制和八进制表示法，它们会被编译为十进制数字</p>
</blockquote>
<h3 id="2-1-3-字符串"><a href="#2-1-3-字符串" class="headerlink" title="2.1.3 字符串"></a>2.1.3 字符串</h3><blockquote>
<p>使用 <code>string</code> 定义字符串类型：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> myName: string = <span class="string">'Tom'</span>;</span><br><span class="line"><span class="keyword">let</span> myAge: number = <span class="number">25</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 模板字符串</span></span><br><span class="line"><span class="keyword">let</span> sentence: string = <span class="string">`Hello, my name is <span class="subst">$&#123;myName&#125;</span>.</span></span><br><span class="line"><span class="string">I'll be <span class="subst">$&#123;myAge + <span class="number">1</span>&#125;</span> years old next month.`</span>;</span><br></pre></td></tr></table></figure>
<h3 id="2-1-4-空值"><a href="#2-1-4-空值" class="headerlink" title="2.1.4 空值"></a>2.1.4 空值</h3><blockquote>
<p><code>JavaScript</code> 没有空值（<code>Void</code>）的概念，在 <code>TypeScript</code> 中，可以用 <code>void</code> 表示没有任何返回值的函数</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">alertName</span>(<span class="params"></span>): <span class="title">void</span> </span>&#123;</span><br><span class="line">    alert(<span class="string">'My name is Tom'</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>声明一个 <code>void</code> 类型的变量没有什么用，因为你只能将它赋值为 <code>undefined</code>和 <code>null</code>：</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">let unusable: void = undefined;</span><br></pre></td></tr></table></figure>
<h3 id="2-1-5-Null-和-Undefined"><a href="#2-1-5-Null-和-Undefined" class="headerlink" title="2.1.5 Null 和 Undefined"></a>2.1.5 Null 和 Undefined</h3><blockquote>
<p>在 <code>TypeScript</code> 中，可以使用 <code>null</code> 和 <code>undefined</code>来定义这两个原始数据类型：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> u: <span class="literal">undefined</span> = <span class="literal">undefined</span>;</span><br><span class="line"><span class="keyword">let</span> n: <span class="literal">null</span> = <span class="literal">null</span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p><code>undefined</code> 类型的变量只能被赋值为 <code>undefined</code>，<code>null</code> 类型的变量只能被赋值为 <code>null</code></p>
</blockquote>
<ul>
<li>与 <code>void</code> 的区别是，<code>undefined</code>和 <code>null</code> 是所有类型的子类型。也就是说 <code>undefined</code> 类型的变量，可以赋值给 <code>number</code> 类型的变量</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 这样不会报错</span></span><br><span class="line"><span class="keyword">let</span> num: number = <span class="literal">undefined</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 这样也不会报错</span></span><br><span class="line"><span class="keyword">let</span> u: <span class="literal">undefined</span>;</span><br><span class="line"><span class="keyword">let</span> num: number = u;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>而 <code>void</code> 类型的变量不能赋值给 <code>number</code> 类型的变量：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> u: <span class="keyword">void</span>;</span><br><span class="line"><span class="keyword">let</span> num: number = u;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(2,5): error TS2322: Type 'void' is not assignable to type 'number'.</span></span><br></pre></td></tr></table></figure>
<h2 id="2-2-任意值Any"><a href="#2-2-任意值Any" class="headerlink" title="2.2 任意值Any"></a>2.2 任意值Any</h2><blockquote>
<p>如果是一个普通类型，在赋值过程中改变类型是不被允许的</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> myFavoriteNumber: string = <span class="string">'seven'</span>;</span><br><span class="line">myFavoriteNumber = <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>但如果是 <code>any</code> 类型，则允许被赋值为任意类型。</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> myFavoriteNumber: any = <span class="string">'seven'</span>;</span><br><span class="line">myFavoriteNumber = <span class="number">7</span>;</span><br></pre></td></tr></table></figure>
<p><strong>任意值的属性和方法</strong></p>
<p>在任意值上访问任何属性都是允许的：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> anyThing: any = <span class="string">'hello'</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(anyThing.myName);</span><br><span class="line"><span class="built_in">console</span>.log(anyThing.myName.firstName);</span><br></pre></td></tr></table></figure>
<p><strong>也允许调用任何方法</strong>：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> anyThing: any = <span class="string">'Tom'</span>;</span><br><span class="line"></span><br><span class="line">anyThing.setName(<span class="string">'Jerry'</span>);</span><br><span class="line">anyThing.setName(<span class="string">'Jerry'</span>).sayHello();</span><br><span class="line">anyThing.myName.setFirstName(<span class="string">'Cat'</span>);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>可以认为，声明一个变量为任意值之后，对它的任何操作，返回的内容的类型都是任意值</p>
</blockquote>
<p><strong>未声明类型的变量</strong></p>
<blockquote>
<p>变量如果在声明的时候，未指定其类型，那么它会被识别为任意值类型：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> something;</span><br><span class="line">something = <span class="string">'seven'</span>;</span><br><span class="line">something = <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line">something.setName(<span class="string">'Tom'</span>);</span><br></pre></td></tr></table></figure>
<p>等价于</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> something: any;</span><br><span class="line">something = <span class="string">'seven'</span>;</span><br><span class="line">something = <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line">something.setName(<span class="string">'Tom'</span>);</span><br></pre></td></tr></table></figure>
<h2 id="2-3-类型推论"><a href="#2-3-类型推论" class="headerlink" title="2.3 类型推论"></a>2.3 类型推论</h2><blockquote>
<p>如果没有明确的指定类型，那么 <code>TypeScript</code> 会依照类型推论（<code>Type Inference</code>）的规则推断出一个类型</p>
</blockquote>
<p><strong>什么是类型推论</strong></p>
<p>以下代码虽然没有指定类型，但是会在编译的时候报错：</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">let myFavoriteNumber = &apos;seven&apos;;</span><br><span class="line">myFavoriteNumber = 7;</span><br><span class="line"></span><br><span class="line">// index.ts(2,1): error TS2322: Type &apos;number&apos; is not assignable to type &apos;string&apos;.</span><br></pre></td></tr></table></figure>
<p>事实上，它等价于：</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">let myFavoriteNumber: string = &apos;seven&apos;;</span><br><span class="line">myFavoriteNumber = 7;</span><br><span class="line"></span><br><span class="line">// index.ts(2,1): error TS2322: Type &apos;number&apos; is not assignable to type &apos;string&apos;.</span><br></pre></td></tr></table></figure>
<p><code>TypeScript</code> 会在没有明确的指定类型的时候推测出一个类型，这就是类型推论</p>
<p><strong>如果定义的时候没有赋值，不管之后有没有赋值，都会被推断成 any 类型而完全不被类型检查</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> myFavoriteNumber;</span><br><span class="line"></span><br><span class="line">myFavoriteNumber = <span class="string">'seven'</span>;</span><br><span class="line">myFavoriteNumber = <span class="number">7</span>;</span><br></pre></td></tr></table></figure>
<h2 id="2-4-联合类型"><a href="#2-4-联合类型" class="headerlink" title="2.4 联合类型"></a>2.4 联合类型</h2><blockquote>
<p>联合类型（<code>Union Types</code>）表示取值可以为多种类型中的一种</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 简单例子</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> myFavoriteNumber: string | number;</span><br><span class="line">myFavoriteNumber = <span class="string">'seven'</span>;</span><br><span class="line">myFavoriteNumber = <span class="number">7</span>;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> myFavoriteNumber: string | number;</span><br><span class="line">myFavoriteNumber = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(2,1): error TS2322: Type 'boolean' is not assignable to type 'string | number'.</span></span><br><span class="line"><span class="comment">//   Type 'boolean' is not assignable to type 'number'.</span></span><br></pre></td></tr></table></figure>
<ul>
<li>联合类型使用 <code>|</code> 分隔每个类型。</li>
<li>这里的 <code>let myFavoriteNumber: string | number</code> 的含义是，允许 <code>myFavoriteNumber</code> 的类型是 <code>string</code> 或者 <code>number</code>，但是不能是其他类型</li>
</ul>
<p><strong>访问联合类型的属性或方法</strong></p>
<blockquote>
<p>当 <code>TypeScript</code> 不确定一个联合类型的变量到底是哪个类型的时候，我们只能访问此联合类型的所有类型里共有的属性或方法</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getLength</span>(<span class="params">something: string | number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> something.length;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// length 不是 string 和 number 的共有属性，所以会报错</span></span><br><span class="line"><span class="comment">// index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'.</span></span><br><span class="line"><span class="comment">//   Property 'length' does not exist on type 'number'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>访问 <code>string</code> 和 <code>number</code> 的共有属性是没问题的</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getString</span>(<span class="params">something: string | number</span>): <span class="title">string</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> something.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>联合类型的变量在被赋值的时候，会根据类型推论的规则推断出一个类型</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> myFavoriteNumber: string | number;</span><br><span class="line">myFavoriteNumber = <span class="string">'seven'</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(myFavoriteNumber.length); <span class="comment">// 5</span></span><br><span class="line"></span><br><span class="line">myFavoriteNumber = <span class="number">7</span>;</span><br><span class="line"><span class="built_in">console</span>.log(myFavoriteNumber.length); <span class="comment">// 编译时报错</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(5,30): error TS2339: Property 'length' does not exist on type 'number'.</span></span><br></pre></td></tr></table></figure>
<ul>
<li>上例中，第二行的 <code>myFavoriteNumber</code> 被推断成了 <code>string</code>，访问它的 <code>length</code> 属性不会报错。</li>
<li>而第四行的 <code>myFavoriteNumber</code> 被推断成了 <code>number</code>，访问它的 <code>length</code> 属性时就报错了</li>
</ul>
<h2 id="2-5-对象的类型——接口"><a href="#2-5-对象的类型——接口" class="headerlink" title="2.5 对象的类型——接口"></a>2.5 对象的类型——接口</h2><h3 id="2-5-1-简单例子"><a href="#2-5-1-简单例子" class="headerlink" title="2.5.1 简单例子"></a>2.5.1 简单例子</h3><blockquote>
<p>在 <code>TypeScript</code> 中，我们使用接口（<code>Interfaces</code>）来定义对象的类型</p>
</blockquote>
<p><strong>什么是接口</strong></p>
<ul>
<li>在面向对象语言中，接口（<code>Interfaces</code>）是一个很重要的概念，它是对行为的抽象，而具体如何行动需要由类（<code>classes</code>）去实现（<code>implements</code>）。</li>
<li><code>TypeScript</code> 中的接口是一个非常灵活的概念，除了可用于对类的一部分行为进行抽象以外，也常用于对「对象的形状（<code>Shape</code>）」进行描述。</li>
</ul>
<p>接口一般首字母大写</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Person &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    age: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    age: <span class="number">25</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>上面的例子中，我们定义了一个接口 <code>Person</code>，接着定义了一个变量 <code>tom</code>，它的类型是 <code>Person</code>。这样，我们就约束了 <code>tom</code> 的形状必须和接口 <code>Person</code> 一致</p>
</blockquote>
<p><strong>定义的变量比接口少了一些属性是不允许的</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Person &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    age: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(6,5): error TS2322: Type '&#123; name: string; &#125;' is not assignable to type 'Person'.</span></span><br><span class="line"><span class="comment">//   Property 'age' is missing in type '&#123; name: string; &#125;'.</span></span><br></pre></td></tr></table></figure>
<p><strong>多一些属性也是不允许的</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Person &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    age: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    age: <span class="number">25</span>,</span><br><span class="line">    gender: <span class="string">'male'</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(9,5): error TS2322: Type '&#123; name: string; age: number; gender: string; &#125;' is not assignable to type 'Person'.</span></span><br><span class="line"><span class="comment">//   Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>可见，赋值的时候，变量的形状必须和接口的形状保持一致。</p>
</blockquote>
<h3 id="2-5-2-可选属性"><a href="#2-5-2-可选属性" class="headerlink" title="2.5.2 可选属性"></a>2.5.2 可选属性</h3><blockquote>
<p>有时我们希望不要完全匹配一个形状，那么可以用可选属性</p>
</blockquote>
<p>可选属性的含义是该属性可以不存在</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Person &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    age?: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Person &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    age?: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    age: <span class="number">25</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="2-5-3-任意属性"><a href="#2-5-3-任意属性" class="headerlink" title="2.5.3 任意属性"></a>2.5.3 任意属性</h3><blockquote>
<p>有时候我们希望一个接口允许有任意的属性，可以使用如下方式</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Person &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    age?: number;</span><br><span class="line">    [propName: string]: any;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    gender: <span class="string">'male'</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<ul>
<li>使用 <code>[propName: string]</code> 定义了任意属性取 <code>string</code> 类型的值</li>
<li>需要注意的是，<strong>一旦定义了任意属性，那么确定属性和可选属性都必须是它的子属性</strong></li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Person &#123;</span><br><span class="line">    name: string;</span><br><span class="line">    age?: number;</span><br><span class="line">    [propName: string]: string;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    age: <span class="number">25</span>,</span><br><span class="line">    gender: <span class="string">'male'</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(3,5): error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'.</span></span><br><span class="line"><span class="comment">// index.ts(7,5): error TS2322: Type '&#123; [x: string]: string | number; name: string; age: number; gender: string; &#125;' is not assignable to type 'Person'.</span></span><br><span class="line"><span class="comment">//   Index signatures are incompatible.</span></span><br><span class="line"><span class="comment">//     Type 'string | number' is not assignable to type 'string'.</span></span><br><span class="line"><span class="comment">//       Type 'number' is not assignable to type 'string'.</span></span><br></pre></td></tr></table></figure>
<ul>
<li>上例中，任意属性的值允许是 <code>string</code>，但是可选属性 <code>age</code> 的值却是 <code>number</code>，<code>number</code>不是 <code>string</code> 的子属性，所以报错了。</li>
<li>另外，在报错信息中可以看出，此时 <code>{ name: &#39;Tom&#39;, age: 25, gender: &#39;male&#39; }</code>的类型被推断成了 <code>{ [x: string]: string | number; name: string; age: number; gender: string; }</code>，这是联合类型和接口的结合</li>
</ul>
<h3 id="2-5-4-只读属性"><a href="#2-5-4-只读属性" class="headerlink" title="2.5.4 只读属性"></a>2.5.4 只读属性</h3><blockquote>
<p>有时候我们希望对象中的一些字段只能在创建的时候被赋值，那么可以用 <code>readonly</code>定义只读属性</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Person &#123;</span><br><span class="line">    readonly id: number;</span><br><span class="line">    name: string;</span><br><span class="line">    age?: number;</span><br><span class="line">    [propName: string]: any;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    id: <span class="number">89757</span>,</span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    gender: <span class="string">'male'</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">tom.id = <span class="number">9527</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上例中，使用 <code>readonly</code> 定义的属性 <code>id</code> 初始化后，又被赋值了，所以报错了</p>
</blockquote>
<p><strong>注意，只读的约束存在于第一次给对象赋值的时候，而不是第一次给只读属性赋值的时候</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Person &#123;</span><br><span class="line">    readonly id: number;</span><br><span class="line">    name: string;</span><br><span class="line">    age?: number;</span><br><span class="line">    [propName: string]: any;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> tom: Person = &#123;</span><br><span class="line">    name: <span class="string">'Tom'</span>,</span><br><span class="line">    gender: <span class="string">'male'</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">tom.id = <span class="number">89757</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(8,5): error TS2322: Type '&#123; name: string; gender: string; &#125;' is not assignable to type 'Person'.</span></span><br><span class="line"><span class="comment">//   Property 'id' is missing in type '&#123; name: string; gender: string; &#125;'.</span></span><br><span class="line"><span class="comment">// index.ts(13,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.</span></span><br></pre></td></tr></table></figure>
<ul>
<li>上例中，报错信息有两处，第一处是在对 <code>tom</code> 进行赋值的时候，没有给 <code>id</code> 赋值。</li>
<li>第二处是在给 <code>tom.id</code> 赋值的时候，由于它是只读属性，所以报错了</li>
</ul>
<h2 id="2-6-数组的类型"><a href="#2-6-数组的类型" class="headerlink" title="2.6 数组的类型"></a>2.6 数组的类型</h2><blockquote>
<p>在 <code>TypeScript</code> 中，数组类型有多种定义方式，比较灵活。</p>
</blockquote>
<h3 id="2-6-1「类型-方括号」表示法"><a href="#2-6-1「类型-方括号」表示法" class="headerlink" title="2.6.1「类型 + 方括号」表示法"></a>2.6.1「类型 + 方括号」表示法</h3><blockquote>
<p>最简单的方法是使用「类型 + 方括号」来表示数组：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> fibonacci: number[] = [<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>];</span><br></pre></td></tr></table></figure>
<blockquote>
<p>数组的项中不允许出现其他的类型</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> fibonacci: number[] = [<span class="number">1</span>, <span class="string">'1'</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(1,5): error TS2322: Type '(number | string)[]' is not assignable to type 'number[]'.</span></span><br><span class="line"><span class="comment">//   Type 'number | string' is not assignable to type 'number'.</span></span><br><span class="line"><span class="comment">//     Type 'string' is not assignable to type 'number'.</span></span><br></pre></td></tr></table></figure>
<ul>
<li>上例中，<code>[1, &#39;1&#39;, 2, 3, 5]</code> 的类型被推断为 <code>(number | string)[]</code>，这是联合类型和数组的结合。</li>
<li>数组的一些方法的参数也会根据数组在定义时约定的类型进行限制</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> fibonacci: number[] = [<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>];</span><br><span class="line">fibonacci.push(<span class="string">'8'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(2,16): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上例中，<code>push</code> 方法只允许传入 <code>number</code> 类型的参数，但是却传了一个 <code>string</code> 类型的参数，所以报错了</p>
</blockquote>
<h3 id="2-6-2-数组泛型"><a href="#2-6-2-数组泛型" class="headerlink" title="2.6.2 数组泛型"></a>2.6.2 数组泛型</h3><blockquote>
<p>也可以使用数组泛型（<code>Array Generic</code>）<code>Array&lt;elemType&gt;</code>来表示数组</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> fibonacci: <span class="built_in">Array</span>&lt;number&gt; = [<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>];</span><br></pre></td></tr></table></figure>
<h3 id="2-6-3-用接口表示数组"><a href="#2-6-3-用接口表示数组" class="headerlink" title="2.6.3 用接口表示数组"></a>2.6.3 用接口表示数组</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface NumberArray &#123;</span><br><span class="line">    [index: number]: number;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> fibonacci: NumberArray = [<span class="number">1</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>];</span><br></pre></td></tr></table></figure>
<blockquote>
<p><code>NumberArray</code> 表示：只要 <code>index</code> 的类型是 <code>number</code>，那么值的类型必须是 <code>number</code></p>
</blockquote>
<h3 id="2-6-4-any-在数组中的应用"><a href="#2-6-4-any-在数组中的应用" class="headerlink" title="2.6.4 any 在数组中的应用"></a>2.6.4 any 在数组中的应用</h3><blockquote>
<p>一个比较常见的做法是，用 <code>any</code> 表示数组中允许出现任意类型：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> list: any[] = [<span class="string">'poetries'</span>, <span class="number">22</span>, &#123; <span class="attr">website</span>: <span class="string">'http://blog.poetries.top'</span> &#125;];</span><br></pre></td></tr></table></figure>
<h3 id="2-6-5-类数组"><a href="#2-6-5-类数组" class="headerlink" title="2.6.5 类数组"></a>2.6.5 类数组</h3><blockquote>
<p>类数组（<code>Array-like Object</code>）不是数组类型，比如 <code>arguments</code></p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> args: number[] = <span class="built_in">arguments</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(2,7): error TS2322: Type 'IArguments' is not assignable to type 'number[]'.</span></span><br><span class="line"><span class="comment">//   Property 'push' is missing in type 'IArguments'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>事实上常见的类数组都有自己的接口定义，如 <code>IArguments</code>, <code>NodeList</code>, <code>HTMLCollection</code> 等：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> args: IArguments = <span class="built_in">arguments</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="2-7-函数的类型"><a href="#2-7-函数的类型" class="headerlink" title="2.7 函数的类型"></a>2.7 函数的类型</h2><h3 id="2-7-1-函数声明"><a href="#2-7-1-函数声明" class="headerlink" title="2.7.1 函数声明"></a>2.7.1 函数声明</h3><blockquote>
<p>在 <code>JavaScript</code> 中，有两种常见的定义函数的方式——函数声明（<code>Function Declaration</code>）和函数表达式（<code>Function Expression</code>）</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 函数声明（Function Declaration）</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params">x, y</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 函数表达式（Function Expression）</span></span><br><span class="line"><span class="keyword">let</span> mySum = <span class="function"><span class="keyword">function</span> (<span class="params">x, y</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>一个函数有输入和输出，要在 <code>TypeScript</code> 中对其进行约束，需要把输入和输出都考虑到，其中函数声明的类型定义较简单</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params">x: number, y: number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>注意，输入多余的（或者少于要求的）参数，是不被允许的：</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params">x: number, y: number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;</span><br><span class="line">sum(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.</span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params">x: number, y: number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;</span><br><span class="line">sum(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.</span></span><br></pre></td></tr></table></figure>
<h3 id="2-7-2-函数表达式"><a href="#2-7-2-函数表达式" class="headerlink" title="2.7.2 函数表达式"></a>2.7.2 函数表达式</h3><blockquote>
<p>如果要我们现在写一个对函数表达式（<code>Function Expression</code>）的定义，可能会写成这样</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> mySum = <span class="function"><span class="keyword">function</span> (<span class="params">x: number, y: number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>这是可以通过编译的，不过事实上，上面的代码只对等号右侧的匿名函数进行了类型定义，而等号左边的 <code>mySum</code>，是通过赋值操作进行类型推论而推断出来的。如果需要我们手动给 <code>mySum</code> 添加类型，则应该是这样</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// =&gt;左边 (x: number, y: number) 是输入类型 </span></span><br><span class="line"><span class="comment">// =&gt;右边number是输出类型</span></span><br><span class="line"><span class="keyword">let</span> mySum: <span class="function">(<span class="params">x: number, y: number</span>) =&gt;</span> number = <span class="function"><span class="keyword">function</span> (<span class="params">x: number, y: number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p><strong>注意不要混淆了 TypeScript 中的 =&gt; 和 ES6 中的 =&gt;</strong></p>
<blockquote>
<p>在 <code>TypeScript</code> 的类型定义中，<code>=&gt;</code> 用来表示函数的定义，左边是输入类型，需要用括号括起来，右边是输出类型。</p>
</blockquote>
<h3 id="2-7-3-用接口定义函数的形状"><a href="#2-7-3-用接口定义函数的形状" class="headerlink" title="2.7.3 用接口定义函数的形状"></a>2.7.3 用接口定义函数的形状</h3><blockquote>
<p>我们也可以使用接口的方式来定义一个函数需要符合的形状</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface SearchFunc &#123;</span><br><span class="line">    (source: string, <span class="attr">subString</span>: string): boolean;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> mySearch: SearchFunc;</span><br><span class="line">mySearch = <span class="function"><span class="keyword">function</span>(<span class="params">source: string, subString: string</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> source.search(subString) !== <span class="number">-1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>需要注意的是，可选参数必须接在必需参数后面。换句话说，可选参数后面不允许再出现必须参数了</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">buildName</span>(<span class="params">firstName?: string, lastName: string</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (firstName) &#123;</span><br><span class="line">        <span class="keyword">return</span> firstName + <span class="string">' '</span> + lastName;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> lastName;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> tomcat = buildName(<span class="string">'Tom'</span>, <span class="string">'Cat'</span>);</span><br><span class="line"><span class="keyword">let</span> tom = buildName(<span class="literal">undefined</span>, <span class="string">'Tom'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(1,40): error TS1016: A required parameter cannot follow an optional parameter.</span></span><br></pre></td></tr></table></figure>
<h3 id="2-7-4-参数默认值"><a href="#2-7-4-参数默认值" class="headerlink" title="2.7.4 参数默认值"></a>2.7.4 参数默认值</h3><blockquote>
<p>在 <code>ES6</code>中，我们允许给函数的参数添加默认值，<code>TypeScript</code> 会将添加了默认值的参数识别为可选参数</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">buildName</span>(<span class="params">firstName: string, lastName: string = <span class="string">'Cat'</span></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> firstName + <span class="string">' '</span> + lastName;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> tomcat = buildName(<span class="string">'Tom'</span>, <span class="string">'Cat'</span>);</span><br><span class="line"><span class="keyword">let</span> tom = buildName(<span class="string">'Tom'</span>);</span><br></pre></td></tr></table></figure>
<p><strong>此时就不受「可选参数必须接在必需参数后面」的限制了</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">buildName</span>(<span class="params">firstName: string = <span class="string">'Tom'</span>, lastName: string</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> firstName + <span class="string">' '</span> + lastName;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> tomcat = buildName(<span class="string">'Tom'</span>, <span class="string">'Cat'</span>);</span><br><span class="line"><span class="keyword">let</span> cat = buildName(<span class="literal">undefined</span>, <span class="string">'Cat'</span>);</span><br></pre></td></tr></table></figure>
<h3 id="2-7-5-剩余参数"><a href="#2-7-5-剩余参数" class="headerlink" title="2.7.5 剩余参数"></a>2.7.5 剩余参数</h3><blockquote>
<p>ES6 中，可以使用 <code>...rest</code> 的方式获取函数中的剩余参数（<code>rest</code> 参数）</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">push</span>(<span class="params">array, ...items</span>) </span>&#123;</span><br><span class="line">    items.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">item</span>) </span>&#123;</span><br><span class="line">        array.push(item);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = [];</span><br><span class="line">push(a, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>事实上，items 是一个数组。所以我们可以用数组的类型来定义它</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">push</span>(<span class="params">array: any[], ...items: any[]</span>) </span>&#123;</span><br><span class="line">    items.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">item</span>) </span>&#123;</span><br><span class="line">        array.push(item);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = [];</span><br><span class="line">push(a, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>注意，rest 参数只能是最后一个参数</p>
</blockquote>
<h3 id="2-7-6-函数重载"><a href="#2-7-6-函数重载" class="headerlink" title="2.7.6 函数重载"></a>2.7.6 函数重载</h3><ul>
<li>重载允许一个函数接受不同数量或类型的参数时，作出不同的处理。</li>
</ul>
<blockquote>
<p>比如，我们需要实现一个函数 <code>reverse</code>，输入数字 <code>123</code> 的时候，输出反转的数字 <code>321</code>，输入字符串 <code>&#39;hello&#39;</code> 的时候，输出反转的字符串 <code>&#39;olleh&#39;</code></p>
</blockquote>
<p><strong>利用联合类型，我们可以这么实现</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">reverse</span>(<span class="params">x: number | string</span>): <span class="title">number</span> | <span class="title">string</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> x === <span class="string">'number'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">Number</span>(x.toString().split(<span class="string">''</span>).reverse().join(<span class="string">''</span>));</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> x === <span class="string">'string'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> x.split(<span class="string">''</span>).reverse().join(<span class="string">''</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>然而这样有一个缺点，就是不能够精确的表达，输入为数字的时候，输出也应该为数字，输入为字符串的时候，输出也应该为字符串</p>
</blockquote>
<p><strong>这时，我们可以使用重载定义多个 reverse 的函数类型</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">reverse</span>(<span class="params">x: number</span>): <span class="title">number</span>;</span></span><br><span class="line"><span class="function"><span class="title">function</span> <span class="title">reverse</span>(<span class="params">x: string</span>): <span class="title">string</span>;</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="title">function</span> <span class="title">reverse</span>(<span class="params">x: number | string</span>): <span class="title">number</span> | <span class="title">string</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> x === <span class="string">'number'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">Number</span>(x.toString().split(<span class="string">''</span>).reverse().join(<span class="string">''</span>));</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> x === <span class="string">'string'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> x.split(<span class="string">''</span>).reverse().join(<span class="string">''</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>上例中，我们重复定义了多次函数 <code>reverse</code>，前几次都是函数定义，最后一次是函数实现。在编辑器的代码提示中，可以正确的看到前两个提示。</li>
</ul>
<blockquote>
<p><strong>注意</strong>，<code>TypeScript</code> 会优先从最前面的函数定义开始匹配，所以多个函数定义如果有包含关系，需要优先把精确的定义写在前面</p>
</blockquote>
<h2 id="2-8-类型断言"><a href="#2-8-类型断言" class="headerlink" title="2.8 类型断言"></a>2.8 类型断言</h2><blockquote>
<p>类型断言（<code>Type Assertion</code>）可以用来手动指定一个值的类型。</p>
</blockquote>
<p><strong>语法</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">&lt;类型&gt;值</span><br><span class="line"></span><br><span class="line">// 或</span><br><span class="line"></span><br><span class="line">值 as 类型</span><br></pre></td></tr></table></figure>
<blockquote>
<p>在 <code>tsx</code> 语法（<code>React</code> 的 <code>jsx</code> 语法的 <code>ts</code> 版）中必须用后一种</p>
</blockquote>
<p><strong>例子：将一个联合类型的变量指定为一个更加具体的类型</strong></p>
<blockquote>
<p>当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候，我们只能访问此联合类型的所有类型里共有的属性或方法</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getLength</span>(<span class="params">something: string | number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> something.length;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'.</span></span><br><span class="line"><span class="comment">//   Property 'length' does not exist on type 'number'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>而有时候，我们确实需要在还不确定类型的时候就访问其中一个类型的属性或方法，比如</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getLength</span>(<span class="params">something: string | number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (something.length) &#123;</span><br><span class="line">        <span class="keyword">return</span> something.length;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> something.toString().length;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(2,19): error TS2339: Property 'length' does not exist on type 'string | number'.</span></span><br><span class="line"><span class="comment">//   Property 'length' does not exist on type 'number'.</span></span><br><span class="line"><span class="comment">// index.ts(3,26): error TS2339: Property 'length' does not exist on type 'string | number'.</span></span><br><span class="line"><span class="comment">//   Property 'length' does not exist on type 'number'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上例中，获取 <code>something.length</code>的时候会报错</p>
</blockquote>
<p><strong>此时可以使用类型断言，将 something 断言成 string</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getLength</span>(<span class="params">something: string | number</span>): <span class="title">number</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> ((<span class="xml"><span class="tag">&lt;<span class="name">string</span>&gt;</span>something).length) &#123;</span></span><br><span class="line">        return (&lt;string&gt;something).length;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        return something.toString().length;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>类型断言的用法如上，在需要断言的变量前加上 <code>&lt;Type&gt;</code> 即可</p>
</blockquote>
<p><strong>类型断言不是类型转换，断言成一个联合类型中不存在的类型是不允许的</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">toBoolean</span>(<span class="params">something: string | number</span>): <span class="title">boolean</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">boolean</span>&gt;</span>something;</span></span><br><span class="line"><span class="xml">&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="xml">// index.ts(2,10): error TS2352: Type 'string | number' cannot be converted to type 'boolean'.</span></span><br><span class="line"><span class="xml">//   Type 'number' is not comparable to type 'boolean'.</span></span><br></pre></td></tr></table></figure>
<h2 id="2-9-声明文件"><a href="#2-9-声明文件" class="headerlink" title="2.9 声明文件"></a>2.9 声明文件</h2><blockquote>
<p>当使用第三方库时，我们需要引用它的声明文件</p>
</blockquote>
<h3 id="2-9-1-声明-declare-语句"><a href="#2-9-1-声明-declare-语句" class="headerlink" title="2.9.1 声明(declare)语句"></a>2.9.1 声明(declare)语句</h3><blockquote>
<p>假如我们想使用第三方库，比如 <code>jQuery</code>，我们通常这样获取一个 <code>id</code> 是 <code>foo</code> 的元素</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">$(<span class="string">'#foo'</span>);</span><br><span class="line"><span class="comment">// or</span></span><br><span class="line">jQuery(<span class="string">'#foo'</span>);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>但是在 <code>TypeScript</code> 中，我们并不知道 <code>$</code> 或 <code>jQuery</code>是什么东西</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">jQuery(<span class="string">'#foo'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(1,1): error TS2304: Cannot find name 'jQuery'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>这时，我们需要使用 <code>declare</code> 关键字来定义它的类型，帮助<code>TypeScript</code> 判断我们传入的参数类型对不对</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">declare <span class="keyword">var</span> jQuery: <span class="function">(<span class="params">selector: string</span>) =&gt;</span> any;</span><br><span class="line"></span><br><span class="line">jQuery(<span class="string">'#foo'</span>);</span><br></pre></td></tr></table></figure>
<blockquote>
<p><code>declare</code> 定义的类型只会用于编译时的检查，编译结果中会被删除</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//上例的编译结果是：</span></span><br><span class="line"></span><br><span class="line">jQuery(<span class="string">'#foo'</span>);</span><br></pre></td></tr></table></figure>
<h3 id="2-9-2-声明文件-约定-d-ts后缀"><a href="#2-9-2-声明文件-约定-d-ts后缀" class="headerlink" title="2.9.2 声明文件(约定.d.ts后缀)"></a>2.9.2 声明文件(约定.d.ts后缀)</h3><blockquote>
<p>通常我们会把类型声明放到一个单独的文件中，这就是声明文件</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// jQuery.d.ts</span></span><br><span class="line"></span><br><span class="line">declare <span class="keyword">var</span> jQuery: <span class="function">(<span class="params">string</span>) =&gt;</span> any;</span><br></pre></td></tr></table></figure>
<ul>
<li>我们约定声明文件以 <code>.d.ts</code> 为后缀。</li>
<li>然后在使用到的文件的开头，用<code>「三斜线指令」///</code>表示引用了声明文件</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">/// &lt;reference path="./jQuery.d.ts" /&gt;</span></span><br><span class="line"></span><br><span class="line">jQuery(<span class="string">'#foo'</span>);</span><br></pre></td></tr></table></figure>
<h3 id="2-9-3-第三方声明文件"><a href="#2-9-3-第三方声明文件" class="headerlink" title="2.9.3 第三方声明文件"></a>2.9.3 第三方声明文件</h3><blockquote>
<p>当然，<code>jQuery</code> 的声明文件不需要我们定义了，已经有人帮我们定义好了：<a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jquery/index.d.ts" target="_blank" rel="noopener">jQuery in DefinitelyTyped</a></p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jquery/index.d.ts</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Type definitions for jquery 3.3</span></span><br><span class="line"><span class="comment">// Project: https://jquery.com</span></span><br><span class="line"><span class="comment">// Definitions by: Leonard Thieu &lt;https://github.com/leonard-thieu&gt;</span></span><br><span class="line"><span class="comment">//                 Boris Yankov &lt;https://github.com/borisyankov&gt;</span></span><br><span class="line"><span class="comment">//                 Christian Hoffmeister &lt;https://github.com/choffmeister&gt;</span></span><br><span class="line"><span class="comment">//                 Steve Fenton &lt;https://github.com/Steve-Fenton&gt;</span></span><br><span class="line"><span class="comment">//                 Diullei Gomes &lt;https://github.com/Diullei&gt;</span></span><br><span class="line"><span class="comment">//                 Tass Iliopoulos &lt;https://github.com/tasoili&gt;</span></span><br><span class="line"><span class="comment">//                 Jason Swearingen &lt;https://github.com/jasons-novaleaf&gt;</span></span><br><span class="line"><span class="comment">//                 Sean Hill &lt;https://github.com/seanski&gt;</span></span><br><span class="line"><span class="comment">//                 Guus Goossens &lt;https://github.com/Guuz&gt;</span></span><br><span class="line"><span class="comment">//                 Kelly Summerlin &lt;https://github.com/ksummerlin&gt;</span></span><br><span class="line"><span class="comment">//                 Basarat Ali Syed &lt;https://github.com/basarat&gt;</span></span><br><span class="line"><span class="comment">//                 Nicholas Wolverson &lt;https://github.com/nwolverson&gt;</span></span><br><span class="line"><span class="comment">//                 Derek Cicerone &lt;https://github.com/derekcicerone&gt;</span></span><br><span class="line"><span class="comment">//                 Andrew Gaspar &lt;https://github.com/AndrewGaspar&gt;</span></span><br><span class="line"><span class="comment">//                 Seikichi Kondo &lt;https://github.com/seikichi&gt;</span></span><br><span class="line"><span class="comment">//                 Benjamin Jackman &lt;https://github.com/benjaminjackman&gt;</span></span><br><span class="line"><span class="comment">//                 Poul Sorensen &lt;https://github.com/s093294&gt;</span></span><br><span class="line"><span class="comment">//                 Josh Strobl &lt;https://github.com/JoshStrobl&gt;</span></span><br><span class="line"><span class="comment">//                 John Reilly &lt;https://github.com/johnnyreilly&gt;</span></span><br><span class="line"><span class="comment">//                 Dick van den Brink &lt;https://github.com/DickvdBrink&gt;</span></span><br><span class="line"><span class="comment">//                 Thomas Schulz &lt;https://github.com/King2500&gt;</span></span><br><span class="line"><span class="comment">//                 Terry Mun &lt;https://github.com/terrymun&gt;</span></span><br><span class="line"><span class="comment">// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped</span></span><br><span class="line"><span class="comment">// TypeScript Version: 2.3</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 引入声明文件</span></span><br><span class="line"><span class="comment">/// &lt;reference types="sizzle" /&gt;</span></span><br><span class="line"><span class="comment">/// &lt;reference path="JQueryStatic.d.ts" /&gt;</span></span><br><span class="line"><span class="comment">/// &lt;reference path="JQuery.d.ts" /&gt;</span></span><br><span class="line"><span class="comment">/// &lt;reference path="misc.d.ts" /&gt;</span></span><br><span class="line"><span class="comment">/// &lt;reference path="legacy.d.ts" /&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> = jQuery;</span><br></pre></td></tr></table></figure>
<ul>
<li>我们可以直接下载下来使用，但是更推荐的是使用工具统一管理第三方库的声明文件- 社区已经有多种方式引入声明文件，不过 <code>TypeScript 2.0</code>推荐使用 <code>@types</code> 来管理。</li>
<li><code>@types</code> 的使用方式很简单，直接用 <code>npm</code> 安装对应的声明模块即可，以 <code>jQuery</code> 举例</li>
</ul>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">npm install @types/jquery --save-dev</span><br></pre></td></tr></table></figure>
<p><strong>可以在这个页面搜索你需要的声明文件</strong></p>
<blockquote>
<p><a href="http://microsoft.github.io/TypeSearch/" target="_blank" rel="noopener">http://microsoft.github.io/TypeSearch/</a></p>
</blockquote>
<h2 id="2-10-内置对象"><a href="#2-10-内置对象" class="headerlink" title="2.10 内置对象"></a>2.10 内置对象</h2><blockquote>
<p><code>JavaScript</code> 中有很多内置对象，它们可以直接在 <code>TypeScript</code> 中当做定义好了的类型</p>
</blockquote>
<blockquote>
<p>内置对象是指根据标准在全局作用域（<code>Global</code>）上存在的对象。这里的标准是指 <code>ECMAScript</code> 和其他环境（比如 <code>DOM</code>）的标准</p>
</blockquote>
<h3 id="2-10-1-ECMAScript-的内置对象"><a href="#2-10-1-ECMAScript-的内置对象" class="headerlink" title="2.10.1 ECMAScript 的内置对象"></a>2.10.1 ECMAScript 的内置对象</h3><p><strong>ECMAScript 标准提供的内置对象有</strong></p>
<blockquote>
<p><code>Boolean</code>、<code>Error</code>、<code>Date</code>、<code>RegExp</code> 等</p>
</blockquote>
<p>我们可以在 <code>TypeScript</code> 中将变量定义为这些类型：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> b: <span class="built_in">Boolean</span> = <span class="keyword">new</span> <span class="built_in">Boolean</span>(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> e: <span class="built_in">Error</span> = <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'Error occurred'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> d: <span class="built_in">Date</span> = <span class="keyword">new</span> <span class="built_in">Date</span>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> r: <span class="built_in">RegExp</span> = <span class="regexp">/[a-z]/</span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>更多的内置对象，可以查看 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects" target="_blank" rel="noopener">MDN 的文档</a></p>
</blockquote>
<blockquote>
<p>而他们的定义文件，则在 <a href="https://github.com/Microsoft/TypeScript/tree/master/src/lib" target="_blank" rel="noopener">TypeScript 核心库的定义文件中</a></p>
</blockquote>
<h3 id="2-10-2-DOM-和-BOM-的内置对象"><a href="#2-10-2-DOM-和-BOM-的内置对象" class="headerlink" title="2.10.2 DOM 和 BOM 的内置对象"></a>2.10.2 DOM 和 BOM 的内置对象</h3><p><strong>DOM 和 BOM 提供的内置对象有</strong></p>
<blockquote>
<p><code>Document</code>、<code>HTMLElement</code>、<code>Event</code>、<code>NodeList</code> 等。</p>
</blockquote>
<blockquote>
<p>TypeScript 中会经常用到这些类型</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> body: HTMLElement = <span class="built_in">document</span>.body;</span><br><span class="line"><span class="keyword">let</span> allDiv: NodeList = <span class="built_in">document</span>.querySelectorAll(<span class="string">'div'</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">document</span>.addEventListener(<span class="string">'click'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">e: MouseEvent</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// Do something</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>它们的定义文件同样在 <a href="https://github.com/Microsoft/TypeScript/tree/master/src/lib" target="_blank" rel="noopener">TypeScript 核心库的定义文件中</a></p>
</blockquote>
<h3 id="2-10-3-TypeScript-核心库的定义文件"><a href="#2-10-3-TypeScript-核心库的定义文件" class="headerlink" title="2.10.3 TypeScript 核心库的定义文件"></a>2.10.3 TypeScript 核心库的定义文件</h3><blockquote>
<p><a href="https://github.com/Microsoft/TypeScript/tree/master/src/lib" target="_blank" rel="noopener">TypeScript 核心库</a>的定义文件中定义了所有浏览器环境需要用到的类型，并且是预置在 TypeScript 中的</p>
</blockquote>
<blockquote>
<p>当你在使用一些常用的方法的时候，<code>TypeScript</code> 实际上已经帮你做了很多类型判断的工作了，比如</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">Math</span>.pow(<span class="number">10</span>, <span class="string">'2'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(1,14): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上面的例子中，<code>Math.pow</code> 必须接受两个 <code>number</code> 类型的参数。事实上 <code>Math.pow</code>的类型定义如下</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface <span class="built_in">Math</span> &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns the value of a base expression taken to a specified power.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param </span>x The base value of the expression.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param </span>y The exponent value of the expression.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    pow(x: number, <span class="attr">y</span>: number): number;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>再举一个 <code>DOM</code> 中的例子</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="built_in">document</span>.addEventListener(<span class="string">'click'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">e</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(e.targetCurrent);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(2,17): error TS2339: Property 'targetCurrent' does not exist on type 'MouseEvent'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上面的例子中，<code>addEventListener</code> 方法是在 <code>TypeScript</code> 核心库中定义的</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEvent &#123;</span><br><span class="line">    addEventListener(type: string, <span class="attr">listener</span>: <span class="function">(<span class="params">ev: MouseEvent</span>) =&gt;</span> any, useCapture?: boolean): <span class="keyword">void</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>所以 <code>e</code> 被推断成了 <code>MouseEvent</code>，而 <code>MouseEvent</code> 是没有 <code>targetCurrent</code> 属性的，所以报错了</p>
</blockquote>
<p><strong>注意，TypeScript 核心库的定义中不包含 Node.js 部分</strong></p>
<h3 id="2-10-4-用-TypeScript-写-Node-js"><a href="#2-10-4-用-TypeScript-写-Node-js" class="headerlink" title="2.10.4 用 TypeScript 写 Node.js"></a>2.10.4 用 TypeScript 写 Node.js</h3><blockquote>
<p><code>Node.js</code> 不是内置对象的一部分，如果想用 <code>TypeScript</code> 写 <code>Node.js</code>，则需要引入第三方声明文件</p>
</blockquote>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">npm install @types/node --save-dev</span><br></pre></td></tr></table></figure>
<h1 id="三、进阶"><a href="#三、进阶" class="headerlink" title="三、进阶"></a>三、进阶</h1><h2 id="3-1-类型别名"><a href="#3-1-类型别名" class="headerlink" title="3.1 类型别名"></a>3.1 类型别名</h2><blockquote>
<p>类型别名用来给一个类型起个新名字</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">type Name = string;</span><br><span class="line"></span><br><span class="line">type NameResolver = <span class="function"><span class="params">()</span> =&gt;</span> string;</span><br><span class="line"></span><br><span class="line">type NameOrResolver = Name | NameResolver; <span class="comment">// 联合类型</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getName</span>(<span class="params">n: NameOrResolver</span>): <span class="title">Name</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> n === <span class="string">'string'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> n;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> n();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上例中，我们使用 <code>type</code> 创建类型别名。</p>
<blockquote>
<p>类型别名常用于联合类型</p>
</blockquote>
<h2 id="3-2-字符串字面量类型"><a href="#3-2-字符串字面量类型" class="headerlink" title="3.2 字符串字面量类型"></a>3.2 字符串字面量类型</h2><blockquote>
<p>字符串字面量类型用来约束取值只能是某几个字符串中的一个</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">type EventNames = <span class="string">'click'</span> | <span class="string">'scroll'</span> | <span class="string">'mousemove'</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">handleEvent</span>(<span class="params">ele: Element, event: EventNames</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// do something</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">handleEvent(<span class="built_in">document</span>.getElementById(<span class="string">'hello'</span>), <span class="string">'scroll'</span>);  <span class="comment">// 没问题</span></span><br><span class="line">handleEvent(<span class="built_in">document</span>.getElementById(<span class="string">'world'</span>), <span class="string">'dbclick'</span>); <span class="comment">// 报错，event 不能为 'dbclick'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(7,47): error TS2345: Argument of type '"dbclick"' is not assignable to parameter of type 'EventNames'.</span></span><br></pre></td></tr></table></figure>
<ul>
<li>上例中，我们使用 <code>type</code> 定了一个字符串字面量类型 <code>EventNames</code>，它只能取三种字符串中的一种。</li>
</ul>
<p><strong>注意，类型别名与字符串字面量类型都是使用 type 进行定</strong></p>
<h2 id="3-3-元组"><a href="#3-3-元组" class="headerlink" title="3.3 元组"></a>3.3 元组</h2><ul>
<li>数组合并了相同类型的对象，而元组（<code>Tuple</code>）合并了不同类型的对象。</li>
<li>元组起源于函数编程语言,在这些语言中频繁使用元组。</li>
</ul>
<h3 id="3-3-1-简单的例子"><a href="#3-3-1-简单的例子" class="headerlink" title="3.3.1 简单的例子"></a>3.3.1 简单的例子</h3><blockquote>
<p>定义一对值分别为 <code>string</code> 和 <code>number</code>的元组</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">let user: [string, number] = [&apos;poetries&apos;, 22];</span><br></pre></td></tr></table></figure>
<blockquote>
<p>当赋值或访问一个已知索引的元素时，会得到正确的类型</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> user: [string, number];</span><br><span class="line">user[<span class="number">0</span>] = <span class="string">'poetries'</span>;</span><br><span class="line">user[<span class="number">1</span>] = <span class="number">22</span>;</span><br><span class="line"></span><br><span class="line">user[<span class="number">0</span>].slice(<span class="number">1</span>);</span><br><span class="line">user[<span class="number">1</span>].toFixed(<span class="number">2</span>);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>也可以只赋值其中一项</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> user: [string, number];</span><br><span class="line">user[<span class="number">0</span>] = <span class="string">'poetries'</span>;</span><br></pre></td></tr></table></figure>
<h3 id="3-3-2-越界的元素"><a href="#3-3-2-越界的元素" class="headerlink" title="3.3.2 越界的元素"></a>3.3.2 越界的元素</h3><blockquote>
<p>当添加越界的元素时，它的类型会被限制为元组中每个类型的联合类型</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> user: [string, number];</span><br><span class="line">user = [<span class="string">'poetries'</span>, <span class="number">22</span>];</span><br><span class="line">user.push(<span class="string">'http://blog.poetries.top'</span>);</span><br><span class="line">user.push(<span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(4,14): error TS2345: Argument of type 'boolean' is not assignable to parameter of type 'string | number'.</span></span><br><span class="line"><span class="comment">//   Type 'boolean' is not assignable to type 'number'.</span></span><br></pre></td></tr></table></figure>
<h2 id="3-4-枚举"><a href="#3-4-枚举" class="headerlink" title="3.4 枚举"></a>3.4 枚举</h2><blockquote>
<p>枚举（<code>Enum</code>）类型用于取值被限定在一定范围内的场景，比如一周只能有七天，颜色限定为红绿蓝等</p>
</blockquote>
<h3 id="3-4-1-简单的例子"><a href="#3-4-1-简单的例子" class="headerlink" title="3.4.1 简单的例子"></a>3.4.1 简单的例子</h3><blockquote>
<p>枚举使用 <code>enum</code> 关键字来定义：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">enum Days &#123;Sun, Mon, Tue, Wed, Thu, Fri, Sat&#125;;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>枚举成员会被赋值为从 <code>0</code> 开始递增的数字，同时也会对枚举值到枚举名进行反向映射</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">enum Days &#123;Sun, Mon, Tue, Wed, Thu, Fri, Sat&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Sun"</span>] === <span class="number">0</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Mon"</span>] === <span class="number">1</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Tue"</span>] === <span class="number">2</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Sat"</span>] === <span class="number">6</span>); <span class="comment">// true</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="number">0</span>] === <span class="string">"Sun"</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="number">1</span>] === <span class="string">"Mon"</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="number">2</span>] === <span class="string">"Tue"</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="number">6</span>] === <span class="string">"Sat"</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>事实上，上面的例子会被编译为</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> Days;</span><br><span class="line">(<span class="function"><span class="keyword">function</span> (<span class="params">Days</span>) </span>&#123;</span><br><span class="line">    Days[Days[<span class="string">"Sun"</span>] = <span class="number">0</span>] = <span class="string">"Sun"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Mon"</span>] = <span class="number">1</span>] = <span class="string">"Mon"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Tue"</span>] = <span class="number">2</span>] = <span class="string">"Tue"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Wed"</span>] = <span class="number">3</span>] = <span class="string">"Wed"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Thu"</span>] = <span class="number">4</span>] = <span class="string">"Thu"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Fri"</span>] = <span class="number">5</span>] = <span class="string">"Fri"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Sat"</span>] = <span class="number">6</span>] = <span class="string">"Sat"</span>;</span><br><span class="line">&#125;)(Days || (Days = &#123;&#125;));</span><br></pre></td></tr></table></figure>
<h3 id="3-4-2-手动赋值"><a href="#3-4-2-手动赋值" class="headerlink" title="3.4.2 手动赋值"></a>3.4.2 手动赋值</h3><blockquote>
<p>我们也可以给枚举项手动赋值</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">enum Days &#123;Sun = <span class="number">7</span>, Mon = <span class="number">1</span>, Tue, Wed, Thu, Fri, Sat&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Sun"</span>] === <span class="number">7</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Mon"</span>] === <span class="number">1</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Tue"</span>] === <span class="number">2</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Sat"</span>] === <span class="number">6</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上面的例子中，未手动赋值的枚举项会接着上一个枚举项递增</p>
</blockquote>
<p>如果未手动赋值的枚举项与手动赋值的重复了，<code>TypeScript</code> 是不会察觉到这一点的</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">enum Days &#123;Sun = <span class="number">3</span>, Mon = <span class="number">1</span>, Tue, Wed, Thu, Fri, Sat&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Sun"</span>] === <span class="number">3</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Wed"</span>] === <span class="number">3</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="number">3</span>] === <span class="string">"Sun"</span>); <span class="comment">// false</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="number">3</span>] === <span class="string">"Wed"</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上面的例子中，递增到 <code>3</code> 的时候与前面的 <code>Sun</code> 的取值重复了，但是 <code>TypeScript</code> 并没有报错，导致 <code>Days[3]</code>的值先是 <code>&quot;Sun&quot;</code>，而后又被 <code>&quot;Wed&quot;</code> 覆盖了。编译的结果是</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> Days;</span><br><span class="line">(<span class="function"><span class="keyword">function</span> (<span class="params">Days</span>) </span>&#123;</span><br><span class="line">    Days[Days[<span class="string">"Sun"</span>] = <span class="number">3</span>] = <span class="string">"Sun"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Mon"</span>] = <span class="number">1</span>] = <span class="string">"Mon"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Tue"</span>] = <span class="number">2</span>] = <span class="string">"Tue"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Wed"</span>] = <span class="number">3</span>] = <span class="string">"Wed"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Thu"</span>] = <span class="number">4</span>] = <span class="string">"Thu"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Fri"</span>] = <span class="number">5</span>] = <span class="string">"Fri"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Sat"</span>] = <span class="number">6</span>] = <span class="string">"Sat"</span>;</span><br><span class="line">&#125;)(Days || (Days = &#123;&#125;));</span><br></pre></td></tr></table></figure>
<p>所以使用的时候需要注意，最好不要出现这种覆盖的情况。</p>
<blockquote>
<p>手动赋值的枚举项可以不是数字，此时需要使用类型断言来让 <code>tsc</code> 无视类型检查 (编译出的 <code>js</code> 仍然是可用的)：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">enum Days &#123;Sun = <span class="number">7</span>, Mon, Tue, Wed, Thu, Fri, Sat = <span class="xml"><span class="tag">&lt;<span class="name">any</span>&gt;</span>"S"&#125;;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> Days;</span><br><span class="line">(<span class="function"><span class="keyword">function</span> (<span class="params">Days</span>) </span>&#123;</span><br><span class="line">    Days[Days[<span class="string">"Sun"</span>] = <span class="number">7</span>] = <span class="string">"Sun"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Mon"</span>] = <span class="number">8</span>] = <span class="string">"Mon"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Tue"</span>] = <span class="number">9</span>] = <span class="string">"Tue"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Wed"</span>] = <span class="number">10</span>] = <span class="string">"Wed"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Thu"</span>] = <span class="number">11</span>] = <span class="string">"Thu"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Fri"</span>] = <span class="number">12</span>] = <span class="string">"Fri"</span>;</span><br><span class="line">    Days[Days[<span class="string">"Sat"</span>] = <span class="string">"S"</span>] = <span class="string">"Sat"</span>;</span><br><span class="line">&#125;)(Days || (Days = &#123;&#125;));</span><br></pre></td></tr></table></figure>
<blockquote>
<p>当然，手动赋值的枚举项也可以为小数或负数，此时后续未手动赋值的项的递增步长仍为 <code>1</code>：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">enum Days &#123;Sun = <span class="number">7</span>, Mon = <span class="number">1.5</span>, Tue, Wed, Thu, Fri, Sat&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Sun"</span>] === <span class="number">7</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Mon"</span>] === <span class="number">1.5</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Tue"</span>] === <span class="number">2.5</span>); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(Days[<span class="string">"Sat"</span>] === <span class="number">6.5</span>); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<h3 id="3-4-3-常数项和计算所得项"><a href="#3-4-3-常数项和计算所得项" class="headerlink" title="3.4.3 常数项和计算所得项"></a>3.4.3 常数项和计算所得项</h3><blockquote>
<p>枚举项有两种类型：常数项（<code>constant member</code>）和计算所得项（<code>computed member</code>）</p>
</blockquote>
<p>前面我们所举的例子都是常数项，一个典型的计算所得项的例子：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">enum Color &#123;Red, Green, Blue = <span class="string">"blue"</span>.length&#125;;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>上面的例子中，<code>&quot;blue&quot;.length</code> 就是一个计算所得项。</p>
</blockquote>
<p>上面的例子不会报错，但是如果紧接在计算所得项后面的是未手动赋值的项，那么它就会因为无法获得初始值而报错</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">enum Color &#123;Red = <span class="string">"red"</span>.length, Green, Blue&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(1,33): error TS1061: Enum member must have initializer.</span></span><br><span class="line"><span class="comment">// index.ts(1,40): error TS1061: Enum member must have initializer.</span></span><br></pre></td></tr></table></figure>
<h3 id="3-4-4-常数枚举"><a href="#3-4-4-常数枚举" class="headerlink" title="3.4.4 常数枚举"></a>3.4.4 常数枚举</h3><blockquote>
<p>常数枚举是使用 <code>const enum</code> 定义的枚举类型</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> enum Directions &#123;</span><br><span class="line">    Up,</span><br><span class="line">    Down,</span><br><span class="line">    Left,</span><br><span class="line">    Right</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];</span><br></pre></td></tr></table></figure>
<blockquote>
<p>常数枚举与普通枚举的区别是，它会在编译阶段被删除，并且不能包含计算成员</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//上例的编译结果是：</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> directions = [<span class="number">0</span> <span class="comment">/* Up */</span>, <span class="number">1</span> <span class="comment">/* Down */</span>, <span class="number">2</span> <span class="comment">/* Left */</span>, <span class="number">3</span> <span class="comment">/* Right */</span>];</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 假如包含了计算成员，则会在编译阶段报错：</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> enum Color &#123;Red, Green, Blue = <span class="string">"blue"</span>.length&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(1,38): error TS2474: In 'const' enum declarations member initializer must be constant expression.</span></span><br></pre></td></tr></table></figure>
<h3 id="3-4-5-外部枚举"><a href="#3-4-5-外部枚举" class="headerlink" title="3.4.5 外部枚举"></a>3.4.5 外部枚举</h3><blockquote>
<p>外部枚举（<code>Ambient Enums</code>）是使用 <code>declare enum</code> 定义的枚举类型</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">declare enum Directions &#123;</span><br><span class="line">    Up,</span><br><span class="line">    Down,</span><br><span class="line">    Left,</span><br><span class="line">    Right</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];</span><br></pre></td></tr></table></figure>
<ul>
<li>之前提到过，<code>declare</code> 定义的类型只会用于编译时的检查，编译结果中会被删除。</li>
</ul>
<p>上例的编译结果是：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];</span><br></pre></td></tr></table></figure>
<ul>
<li>外部枚举与声明语句一样，常出现在声明文件中。</li>
<li>同时使用 <code>declare</code> 和 <code>const</code> 也是可以的：</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">declare <span class="keyword">const</span> enum Directions &#123;</span><br><span class="line">    Up,</span><br><span class="line">    Down,</span><br><span class="line">    Left,</span><br><span class="line">    Right</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 编译结果：</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> directions = [<span class="number">0</span> <span class="comment">/* Up */</span>, <span class="number">1</span> <span class="comment">/* Down */</span>, <span class="number">2</span> <span class="comment">/* Left */</span>, <span class="number">3</span> <span class="comment">/* Right */</span>];</span><br></pre></td></tr></table></figure>
<h2 id="3-5-类"><a href="#3-5-类" class="headerlink" title="3.5 类"></a>3.5 类</h2><h3 id="3-5-1-类的概念"><a href="#3-5-1-类的概念" class="headerlink" title="3.5.1 类的概念"></a>3.5.1 类的概念</h3><blockquote>
<p>类相关的概念做一个简单的介绍</p>
</blockquote>
<ul>
<li>类(<code>Class</code>)：定义了一件事物的抽象特点，包含它的属性和方法</li>
<li>对象（<code>Object</code>）：类的实例，通过 <code>new</code> 生成</li>
<li>面向对象（<code>OOP</code>）的三大特性：封装、继承、多态</li>
<li>封装（<code>Encapsulation</code>）：将对数据的操作细节隐藏起来，只暴露对外的接口。外界调用端不需要（也不可能）知道细节，就能通过对外提供的接口来访问该对象，同时也保证了外界无法任意更改对象内部的数据</li>
<li>继承（<code>Inheritance</code>）：子类继承父类，子类除了拥有父类的所有特性外，还有一些更具体的特性</li>
<li>多态（<code>Polymorphism</code>）：由继承而产生了相关的不同的类，对同一个方法可以有不同的响应。比如 <code>Cat</code> 和 <code>Dog</code> 都继承自 <code>Animal</code>，但是分别实现了自己的 <code>eat</code> 方法。此时针对某一个实例，我们无需了解它是 <code>Cat</code>还是 <code>Dog</code>，就可以直接调用 <code>eat</code>方法，程序会自动判断出来应该如何执行 <code>eat</code></li>
<li>存取器（<code>getter &amp; setter</code>）：用以改变属性的读取和赋值行为</li>
<li>修饰符（<code>Modifiers</code>）：修饰符是一些关键字，用于限定成员或类型的性质。比如 <code>public</code> 表示公有属性或方法</li>
<li>抽象类（<code>Abstract Class</code>）：抽象类是供其他类继承的基类，抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现</li>
<li>接口（<code>Interfaces</code>）：不同类之间公有的属性或方法，可以抽象成一个接口。接口可以被类实现（<code>implements</code>）。一个类只能继承自另一个类，但是可以实现多个接口</li>
</ul>
<h3 id="3-5-2-public-private-和-protected"><a href="#3-5-2-public-private-和-protected" class="headerlink" title="3.5.2 public private 和 protected"></a>3.5.2 public private 和 protected</h3><blockquote>
<p><code>TypeScript</code> 可以使用三种访问修饰符（<code>Access Modifiers</code>），分别是 <code>public</code>、<code>private</code> 和 <code>protected</code></p>
</blockquote>
<ul>
<li><code>public</code> 修饰的属性或方法是公有的，可以在任何地方被访问到，默认所有的属性和方法都是 <code>public</code> 的</li>
<li><code>private</code> 修饰的属性或方法是私有的，不能在声明它的类的外部访问</li>
<li><code>protected</code> 修饰的属性或方法是受保护的，它和 <code>private</code> 类似，区别是它在子类中也是允许被访问的</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    public name;</span><br><span class="line">    public <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a.name); <span class="comment">// Jack</span></span><br><span class="line">a.name = <span class="string">'Tom'</span>;</span><br><span class="line"><span class="built_in">console</span>.log(a.name); <span class="comment">// Tom</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上面的例子中，<code>name</code> 被设置为了 <code>public</code>，所以直接访问实例的 <code>name</code> 属性是允许的。</p>
</blockquote>
<p>很多时候，我们希望有的属性是无法直接存取的，这时候就可以用 <code>private</code> 了</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">lass Animal &#123;</span><br><span class="line">    private name;</span><br><span class="line">    public <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a.name); <span class="comment">// Jack</span></span><br><span class="line">a.name = <span class="string">'Tom'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(9,13): error TS2341: Property 'name' is private and only accessible within class 'Animal'.</span></span><br><span class="line"><span class="comment">// index.ts(10,1): error TS2341: Property 'name' is private and only accessible within class 'Animal'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上面的例子编译后的代码是：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> Animal = (<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">Animal</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Animal;</span><br><span class="line">&#125;());</span><br><span class="line"><span class="keyword">var</span> a = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a.name);</span><br><span class="line">a.name = <span class="string">'Tom'</span>;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>使用 <code>private</code> 修饰的属性或方法，在子类中也是不允许访问的：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    private name;</span><br><span class="line">    public <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">super</span>(name);</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(11,17): error TS2341: Property 'name' is private and only accessible within class 'Animal'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>而如果是用 <code>protected</code> 修饰，则允许在子类中访问</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    protected name;</span><br><span class="line">    public <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">super</span>(name);</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="3-5-3-抽象类"><a href="#3-5-3-抽象类" class="headerlink" title="3.5.3 抽象类"></a>3.5.3 抽象类</h3><blockquote>
<p><code>abstract</code> 用于定义抽象类和其中的抽象方法。</p>
</blockquote>
<p><strong>什么是抽象类？</strong></p>
<blockquote>
<p>首先，抽象类是不允许被实例化的</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">abstract <span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    public name;</span><br><span class="line">    public <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    public abstract sayHi();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(9,11): error TS2511: Cannot create an instance of the abstract class 'Animal'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上面的例子中，我们定义了一个抽象类 <code>Animal</code>，并且定义了一个抽象方法 <code>sayHi</code>。在实例化抽象类的时候报错了。</p>
</blockquote>
<p>其次，抽象类中的抽象方法必须被子类实现</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">abstract <span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    public name;</span><br><span class="line">    public <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    public abstract sayHi();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    public eat() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">`<span class="subst">$&#123;<span class="keyword">this</span>.name&#125;</span> is eating.`</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> cat = <span class="keyword">new</span> Cat(<span class="string">'Tom'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(9,7): error TS2515: Non-abstract class 'Cat' does not implement inherited abstract member 'sayHi' from class 'Animal'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上面的例子中，我们定义了一个类 <code>Cat</code> 继承了抽象类 <code>Animal</code>，但是没有实现抽象方法 <code>sayHi</code>，所以编译报错了。</p>
</blockquote>
<p>下面是一个正确使用抽象类的例子：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">abstract <span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    public name;</span><br><span class="line">    public <span class="keyword">constructor</span>(name) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    public abstract sayHi();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    public sayHi() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">`Meow, My name is <span class="subst">$&#123;<span class="keyword">this</span>.name&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> cat = <span class="keyword">new</span> Cat(<span class="string">'Tom'</span>);</span><br></pre></td></tr></table></figure>
<p>上面的例子中，我们实现了抽象方法 <code>sayHi</code>，编译通过了。</p>
<blockquote>
<p>需要注意的是，即使是抽象方法，<code>TypeScript</code> 的编译结果中，仍然会存在这个类，上面的代码的编译结果是：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> __extends = (<span class="keyword">this</span> &amp;&amp; <span class="keyword">this</span>.__extends) || <span class="function"><span class="keyword">function</span> (<span class="params">d, b</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> p <span class="keyword">in</span> b) <span class="keyword">if</span> (b.hasOwnProperty(p)) d[p] = b[p];</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">__</span>(<span class="params"></span>) </span>&#123; <span class="keyword">this</span>.constructor = d; &#125;</span><br><span class="line">    d.prototype = b === <span class="literal">null</span> ? <span class="built_in">Object</span>.create(b) : (__.prototype = b.prototype, <span class="keyword">new</span> __());</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">var</span> Animal = (<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">Animal</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Animal;</span><br><span class="line">&#125;());</span><br><span class="line"><span class="keyword">var</span> Cat = (<span class="function"><span class="keyword">function</span> (<span class="params">_super</span>) </span>&#123;</span><br><span class="line">    __extends(Cat, _super);</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">Cat</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        _super.apply(<span class="keyword">this</span>, <span class="built_in">arguments</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    Cat.prototype.sayHi = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'Meow, My name is '</span> + <span class="keyword">this</span>.name);</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">return</span> Cat;</span><br><span class="line">&#125;(Animal));</span><br><span class="line"><span class="keyword">var</span> cat = <span class="keyword">new</span> Cat(<span class="string">'Tom'</span>);</span><br></pre></td></tr></table></figure>
<h3 id="3-5-4-类的类型"><a href="#3-5-4-类的类型" class="headerlink" title="3.5.4 类的类型"></a>3.5.4 类的类型</h3><blockquote>
<p>给类加上 <code>TypeScript</code> 的类型很简单，与接口类似：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span> </span>&#123;</span><br><span class="line">    name: string;</span><br><span class="line">    <span class="keyword">constructor</span>(name: string) &#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">    sayHi(): string &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">`My name is <span class="subst">$&#123;<span class="keyword">this</span>.name&#125;</span>`</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a: Animal = <span class="keyword">new</span> Animal(<span class="string">'Jack'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a.sayHi()); <span class="comment">// My name is Jack</span></span><br></pre></td></tr></table></figure>
<h2 id="3-6-类与接口"><a href="#3-6-类与接口" class="headerlink" title="3.6 类与接口"></a>3.6 类与接口</h2><h3 id="3-6-1-类实现接口"><a href="#3-6-1-类实现接口" class="headerlink" title="3.6.1 类实现接口"></a>3.6.1 类实现接口</h3><blockquote>
<p>实现（<code>implements</code>）是面向对象中的一个重要概念。一般来讲，一个类只能继承自另一个类，有时候不同类之间可以有一些共有的特性，这时候就可以把特性提取成接口（<code>interfaces</code>），用 <code>implements</code> 关键字来实现。这个特性大大提高了面向对象的灵活性</p>
</blockquote>
<p>举例来说，门是一个类，防盗门是门的子类。如果防盗门有一个报警器的功能，我们可以简单的给防盗门添加一个报警方法。这时候如果有另一个类，车，也有报警器的功能，就可以考虑把报警器提取出来，作为一个接口，防盗门和车都去实现它</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Alarm &#123;</span><br><span class="line">    alert();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Door</span> </span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SecurityDoor</span> <span class="keyword">extends</span> <span class="title">Door</span> <span class="title">implements</span> <span class="title">Alarm</span> </span>&#123;</span><br><span class="line">    alert() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'SecurityDoor alert'</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span> <span class="title">implements</span> <span class="title">Alarm</span> </span>&#123;</span><br><span class="line">    alert() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'Car alert'</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>一个类可以实现多个接口</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Alarm &#123;</span><br><span class="line">    alert();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">interface Light &#123;</span><br><span class="line">    lightOn();</span><br><span class="line">    lightOff();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Car</span> <span class="title">implements</span> <span class="title">Alarm</span>, <span class="title">Light</span> </span>&#123;</span><br><span class="line">    alert() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'Car alert'</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    lightOn() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'Car light on'</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    lightOff() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'Car light off'</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>上例中，<code>Car</code> 实现了 <code>Alarm</code> 和 <code>Light</code>接口，既能报警，也能开关车灯</p>
</blockquote>
<h3 id="3-6-2-接口继承接口"><a href="#3-6-2-接口继承接口" class="headerlink" title="3.6.2 接口继承接口"></a>3.6.2 接口继承接口</h3><blockquote>
<p>接口与接口之间可以是继承关系</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Alarm &#123;</span><br><span class="line">    alert();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">interface LightableAlarm extends Alarm &#123;</span><br><span class="line">    lightOn();</span><br><span class="line">    lightOff();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>上例中，我们使用 <code>extends</code> 使 <code>LightableAlarm</code> 继承 <code>Alarm</code></p>
</blockquote>
<h3 id="3-6-3-接口继承类"><a href="#3-6-3-接口继承类" class="headerlink" title="3.6.3 接口继承类"></a>3.6.3 接口继承类</h3><blockquote>
<p>接口也可以继承类：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Point</span> </span>&#123;</span><br><span class="line">    x: number;</span><br><span class="line">    y: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">interface Point3d extends Point &#123;</span><br><span class="line">    z: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> point3d: Point3d = &#123;<span class="attr">x</span>: <span class="number">1</span>, <span class="attr">y</span>: <span class="number">2</span>, <span class="attr">z</span>: <span class="number">3</span>&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="3-6-4-混合类型"><a href="#3-6-4-混合类型" class="headerlink" title="3.6.4 混合类型"></a>3.6.4 混合类型</h3><blockquote>
<p>可以使用接口的方式来定义一个函数需要符合的形状</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface SearchFunc &#123;</span><br><span class="line">    (source: string, <span class="attr">subString</span>: string): boolean;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> mySearch: SearchFunc;</span><br><span class="line">mySearch = <span class="function"><span class="keyword">function</span>(<span class="params">source: string, subString: string</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> source.search(subString) !== <span class="number">-1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>有时候，一个函数还可以有自己的属性和方法</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Counter &#123;</span><br><span class="line">    (start: number): string;</span><br><span class="line">    interval: number;</span><br><span class="line">    reset(): <span class="keyword">void</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getCounter</span>(<span class="params"></span>): <span class="title">Counter</span> </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> counter = <span class="xml"><span class="tag">&lt;<span class="name">Counter</span>&gt;</span>function (start: number) &#123; &#125;;</span></span><br><span class="line"><span class="xml">    counter.interval = 123;</span></span><br><span class="line"><span class="xml">    counter.reset = function () &#123; &#125;;</span></span><br><span class="line"><span class="xml">    return counter;</span></span><br><span class="line"><span class="xml">&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="xml">let c = getCounter();</span></span><br><span class="line"><span class="xml">c(10);</span></span><br><span class="line"><span class="xml">c.reset();</span></span><br><span class="line"><span class="xml">c.interval = 5.0;</span></span><br></pre></td></tr></table></figure>
<h2 id="3-7-泛型"><a href="#3-7-泛型" class="headerlink" title="3.7 泛型"></a>3.7 泛型</h2><blockquote>
<p>泛型（<code>Generics</code>）是指在定义函数、接口或类的时候，不预先指定具体的类型，而在使用的时候再指定类型的一种特性</p>
</blockquote>
<h3 id="3-7-1-简单的例子"><a href="#3-7-1-简单的例子" class="headerlink" title="3.7.1 简单的例子"></a>3.7.1 简单的例子</h3><blockquote>
<p>首先，我们来实现一个函数 <code>createArray</code>，它可以创建一个指定长度的数组，同时将每一项都填充一个默认值</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createArray</span>(<span class="params">length: number, value: any</span>): <span class="title">Array</span>&lt;<span class="title">any</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> result = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">        result[i] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">createArray(<span class="number">3</span>, <span class="string">'x'</span>); <span class="comment">// ['x', 'x', 'x']</span></span><br></pre></td></tr></table></figure>
<ul>
<li>上例中，我们使用了之前提到过的数组泛型来定义返回值的类型。</li>
<li>这段代码编译不会报错，但是一个显而易见的缺陷是，它并没有准确的定义返回值的类型：<code>Array&lt;any&gt;</code> 允许数组的每一项都为任意类型。但是我们预期的是，数组中每一项都应该是输入的<code>value</code> 的类型。</li>
</ul>
<blockquote>
<p>这时候，泛型就派上用场了：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createArray</span>&lt;<span class="title">T</span>&gt;(<span class="params">length: number, value: T</span>): <span class="title">Array</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> result: T[] = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">        result[i] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">createArray&lt;string&gt;(<span class="number">3</span>, <span class="string">'x'</span>); <span class="comment">// ['x', 'x', 'x']</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上例中，我们在函数名后添加了 <code>&lt;T&gt;</code>，其中 <code>T</code> 用来指代任意输入的类型，在后面的输入 <code>value: T</code> 和输出 <code>Array&lt;T&gt;</code>中即可使用了</p>
</blockquote>
<p>接着在调用的时候，可以指定它具体的类型为 <code>string</code>。当然，也可以不手动指定，而让类型推论自动推算出来</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createArray</span>&lt;<span class="title">T</span>&gt;(<span class="params">length: number, value: T</span>): <span class="title">Array</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> result: T[] = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">        result[i] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">createArray(<span class="number">3</span>, <span class="string">'x'</span>); <span class="comment">// ['x', 'x', 'x']</span></span><br></pre></td></tr></table></figure>
<h3 id="3-7-2-多个类型参数"><a href="#3-7-2-多个类型参数" class="headerlink" title="3.7.2 多个类型参数"></a>3.7.2 多个类型参数</h3><blockquote>
<p>定义泛型的时候，可以一次定义多个类型参数：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">function swap&lt;T, U&gt;(tuple: [T, U]): [U, T] &#123;</span><br><span class="line">    <span class="keyword">return</span> [tuple[<span class="number">1</span>], tuple[<span class="number">0</span>]];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">swap([<span class="number">7</span>, <span class="string">'seven'</span>]); <span class="comment">// ['seven', 7]</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上例中，我们定义了一个 <code>swap</code> 函数，用来交换输入的元组</p>
</blockquote>
<h3 id="3-7-3-泛型约束"><a href="#3-7-3-泛型约束" class="headerlink" title="3.7.3 泛型约束"></a>3.7.3 泛型约束</h3><blockquote>
<p>在函数内部使用泛型变量的时候，由于事先不知道它是哪种类型，所以不能随意的操作它的属性或方法</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">loggingIdentity</span>&lt;<span class="title">T</span>&gt;(<span class="params">arg: T</span>): <span class="title">T</span> </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(arg.length);</span><br><span class="line">    <span class="keyword">return</span> arg;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(2,19): error TS2339: Property 'length' does not exist on type 'T'.</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上例中，泛型 <code>T</code> 不一定包含属性 <code>length</code>，所以编译的时候报错了。</p>
</blockquote>
<blockquote>
<p>这时，我们可以对泛型进行约束，只允许这个函数传入那些包含<code>length</code> 属性的变量。这就是泛型约束</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Lengthwise &#123;</span><br><span class="line">    length: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">loggingIdentity</span>&lt;<span class="title">T</span> <span class="title">extends</span> <span class="title">Lengthwise</span>&gt;(<span class="params">arg: T</span>): <span class="title">T</span> </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(arg.length);</span><br><span class="line">    <span class="keyword">return</span> arg;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>上例中，我们使用了 <code>extends</code>约束了泛型 <code>T</code> 必须符合接口 <code>Lengthwise</code> 的形状，也就是必须包含 <code>length</code> 属性。</p>
</blockquote>
<blockquote>
<p>此时如果调用 <code>loggingIdentity</code> 的时候，传入的 <code>arg</code>不包含 <code>length</code>，那么在编译阶段就会报错了</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Lengthwise &#123;</span><br><span class="line">    length: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">loggingIdentity</span>&lt;<span class="title">T</span> <span class="title">extends</span> <span class="title">Lengthwise</span>&gt;(<span class="params">arg: T</span>): <span class="title">T</span> </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(arg.length);</span><br><span class="line">    <span class="keyword">return</span> arg;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">loggingIdentity(<span class="number">7</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(10,17): error TS2345: Argument of type '7' is not assignable to parameter of type 'Lengthwise'.</span></span><br></pre></td></tr></table></figure>
<p><strong>多个类型参数之间也可以互相约束：</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">copyFields</span>&lt;<span class="title">T</span> <span class="title">extends</span> <span class="title">U</span>, <span class="title">U</span>&gt;(<span class="params">target: T, source: U</span>): <span class="title">T</span> </span>&#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> id <span class="keyword">in</span> source) &#123;</span><br><span class="line">        target[id] = (<span class="xml"><span class="tag">&lt;<span class="name">T</span>&gt;</span>source)[id];</span></span><br><span class="line"><span class="xml">    &#125;</span></span><br><span class="line"><span class="xml">    return target;</span></span><br><span class="line"><span class="xml">&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="xml">let x = &#123; a: 1, b: 2, c: 3, d: 4 &#125;;</span></span><br><span class="line"></span><br><span class="line"><span class="xml">copyFields(x, &#123; b: 10, d: 20 &#125;);</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>上例中，我们使用了两个类型参数，其中要求 <code>T</code> 继承 <code>U</code>，这样就保证了<code>U</code> 上不会出现 <code>T</code> 中不存在的字段</p>
</blockquote>
<h3 id="3-7-4-泛型接口"><a href="#3-7-4-泛型接口" class="headerlink" title="3.7.4 泛型接口"></a>3.7.4 泛型接口</h3><blockquote>
<p>可以使用接口的方式来定义一个函数需要符合的形状</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface SearchFunc &#123;</span><br><span class="line">  (source: string, <span class="attr">subString</span>: string): boolean;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> mySearch: SearchFunc;</span><br><span class="line">mySearch = <span class="function"><span class="keyword">function</span>(<span class="params">source: string, subString: string</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> source.search(subString) !== <span class="number">-1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>当然也可以使用含有泛型的接口来定义函数的形状</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface CreateArrayFunc &#123;</span><br><span class="line">    &lt;T&gt;(length: number, <span class="attr">value</span>: T): <span class="built_in">Array</span>&lt;T&gt;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> createArray: CreateArrayFunc;</span><br><span class="line">createArray = <span class="function"><span class="keyword">function</span>&lt;<span class="title">T</span>&gt;(<span class="params">length: number, value: T</span>): <span class="title">Array</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> result: T[] = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">        result[i] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">createArray(<span class="number">3</span>, <span class="string">'x'</span>); <span class="comment">// ['x', 'x', 'x']</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>进一步，我们可以把泛型参数提前到接口名上</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface CreateArrayFunc&lt;T&gt; &#123;</span><br><span class="line">    (length: number, <span class="attr">value</span>: T): <span class="built_in">Array</span>&lt;T&gt;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> createArray: CreateArrayFunc&lt;any&gt;;</span><br><span class="line">createArray = <span class="function"><span class="keyword">function</span>&lt;<span class="title">T</span>&gt;(<span class="params">length: number, value: T</span>): <span class="title">Array</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> result: T[] = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">        result[i] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">createArray(<span class="number">3</span>, <span class="string">'x'</span>); <span class="comment">// ['x', 'x', 'x']</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>注意，此时在使用泛型接口的时候，需要定义泛型的类型</p>
</blockquote>
<h3 id="3-7-5-泛型类"><a href="#3-7-5-泛型类" class="headerlink" title="3.7.5 泛型类"></a>3.7.5 泛型类</h3><blockquote>
<p>与泛型接口类似，泛型也可以用于类的类型定义中</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">GenericNumber</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    zeroValue: T;</span><br><span class="line">    add: <span class="function">(<span class="params">x: T, y: T</span>) =&gt;</span> T;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> myGenericNumber = <span class="keyword">new</span> GenericNumber&lt;number&gt;();</span><br><span class="line"></span><br><span class="line">myGenericNumber.zeroValue = <span class="number">0</span>;</span><br><span class="line">myGenericNumber.add = <span class="function"><span class="keyword">function</span>(<span class="params">x, y</span>) </span>&#123; <span class="keyword">return</span> x + y; &#125;;</span><br></pre></td></tr></table></figure>
<h3 id="3-7-6-泛型参数的默认类型"><a href="#3-7-6-泛型参数的默认类型" class="headerlink" title="3.7.6 泛型参数的默认类型"></a>3.7.6 泛型参数的默认类型</h3><blockquote>
<p>在 <code>TypeScript 2.3</code>以后，我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数，从实际值参数中也无法推测出时，这个默认类型就会起作用</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createArray</span>&lt;<span class="title">T</span> = <span class="title">string</span>&gt;(<span class="params">length: number, value: T</span>): <span class="title">Array</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> result: T[] = [];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">        result[i] = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="3-8-声明合并"><a href="#3-8-声明合并" class="headerlink" title="3.8 声明合并"></a>3.8 声明合并</h2><blockquote>
<p>如果定义了两个相同名字的函数、接口或类，那么它们会合并成一个类型</p>
</blockquote>
<h3 id="3-8-1-函数的合并"><a href="#3-8-1-函数的合并" class="headerlink" title="3.8.1 函数的合并"></a>3.8.1 函数的合并</h3><blockquote>
<p>我们可以使用重载定义多个函数类型</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">reverse</span>(<span class="params">x: number</span>): <span class="title">number</span>;</span></span><br><span class="line"><span class="function"><span class="title">function</span> <span class="title">reverse</span>(<span class="params">x: string</span>): <span class="title">string</span>;</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="title">function</span> <span class="title">reverse</span>(<span class="params">x: number | string</span>): <span class="title">number</span> | <span class="title">string</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> x === <span class="string">'number'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">Number</span>(x.toString().split(<span class="string">''</span>).reverse().join(<span class="string">''</span>));</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> x === <span class="string">'string'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> x.split(<span class="string">''</span>).reverse().join(<span class="string">''</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="3-8-2-接口的合并"><a href="#3-8-2-接口的合并" class="headerlink" title="3.8.2 接口的合并"></a>3.8.2 接口的合并</h3><blockquote>
<p>接口中的属性在合并时会简单的合并到一个接口中</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Alarm &#123;</span><br><span class="line">    price: number;</span><br><span class="line">&#125;</span><br><span class="line">interface Alarm &#123;</span><br><span class="line">    weight: number;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>相当于：</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Alarm &#123;</span><br><span class="line">    price: number;</span><br><span class="line">    weight: number;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>注意，合并的属性的类型必须是唯一的</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Alarm &#123;</span><br><span class="line">    price: number;</span><br><span class="line">&#125;</span><br><span class="line">interface Alarm &#123;</span><br><span class="line">    price: number;  <span class="comment">// 虽然重复了，但是类型都是 `number`，所以不会报错</span></span><br><span class="line">    weight: number;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Alarm &#123;</span><br><span class="line">    price: number;</span><br><span class="line">&#125;</span><br><span class="line">interface Alarm &#123;</span><br><span class="line">    price: string;  <span class="comment">// 类型不一致，会报错</span></span><br><span class="line">    weight: number;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// index.ts(5,3): error TS2403: Subsequent variable declarations must have the same type.  Variable 'price' must be of type 'number', but here has type 'string'.</span></span><br></pre></td></tr></table></figure>
<p><strong>接口中方法的合并，与函数的合并一样</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Alarm &#123;</span><br><span class="line">    price: number;</span><br><span class="line">    alert(s: string): string;</span><br><span class="line">&#125;</span><br><span class="line">interface Alarm &#123;</span><br><span class="line">    weight: number;</span><br><span class="line">    alert(s: string, <span class="attr">n</span>: number): string;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>相当于：</p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Alarm &#123;</span><br><span class="line">    price: number;</span><br><span class="line">    weight: number;</span><br><span class="line">    alert(s: string): string;</span><br><span class="line">    alert(s: string, <span class="attr">n</span>: number): string;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="3-8-3-类的合并"><a href="#3-8-3-类的合并" class="headerlink" title="3.8.3 类的合并"></a>3.8.3 类的合并</h3><blockquote>
<p>类的合并与接口的合并规则一致</p>
</blockquote>
<h1 id="四、工程"><a href="#四、工程" class="headerlink" title="四、工程"></a>四、工程</h1><h2 id="4-1-tsconfig-json"><a href="#4-1-tsconfig-json" class="headerlink" title="4.1 tsconfig.json"></a>4.1 tsconfig.json</h2><p><strong>编译选项</strong></p>
<blockquote>
<p>你可以通过 <code>compilerOptions</code> 来定制你的编译选项</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="string">"compilerOptions"</span>: &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 基本选项 */</span></span><br><span class="line">    <span class="string">"target"</span>: <span class="string">"es5"</span>,                       <span class="comment">// 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'</span></span><br><span class="line">    <span class="string">"module"</span>: <span class="string">"commonjs"</span>,                  <span class="comment">// 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'</span></span><br><span class="line">    <span class="string">"lib"</span>: [],                             <span class="comment">// 指定要包含在编译中的库文件</span></span><br><span class="line">    <span class="string">"allowJs"</span>: <span class="literal">true</span>,                       <span class="comment">// 允许编译 javascript 文件</span></span><br><span class="line">    <span class="string">"checkJs"</span>: <span class="literal">true</span>,                       <span class="comment">// 报告 javascript 文件中的错误</span></span><br><span class="line">    <span class="string">"jsx"</span>: <span class="string">"preserve"</span>,                     <span class="comment">// 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'</span></span><br><span class="line">    <span class="string">"declaration"</span>: <span class="literal">true</span>,                   <span class="comment">// 生成相应的 '.d.ts' 文件</span></span><br><span class="line">    <span class="string">"sourceMap"</span>: <span class="literal">true</span>,                     <span class="comment">// 生成相应的 '.map' 文件</span></span><br><span class="line">    <span class="string">"outFile"</span>: <span class="string">"./"</span>,                       <span class="comment">// 将输出文件合并为一个文件</span></span><br><span class="line">    <span class="string">"outDir"</span>: <span class="string">"./"</span>,                        <span class="comment">// 指定输出目录</span></span><br><span class="line">    <span class="string">"rootDir"</span>: <span class="string">"./"</span>,                       <span class="comment">// 用来控制输出目录结构 --outDir.</span></span><br><span class="line">    <span class="string">"removeComments"</span>: <span class="literal">true</span>,                <span class="comment">// 删除编译后的所有的注释</span></span><br><span class="line">    <span class="string">"noEmit"</span>: <span class="literal">true</span>,                        <span class="comment">// 不生成输出文件</span></span><br><span class="line">    <span class="string">"importHelpers"</span>: <span class="literal">true</span>,                 <span class="comment">// 从 tslib 导入辅助工具函数</span></span><br><span class="line">    <span class="string">"isolatedModules"</span>: <span class="literal">true</span>,               <span class="comment">// 将每个文件做为单独的模块 （与 'ts.transpileModule' 类似）.</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 严格的类型检查选项 */</span></span><br><span class="line">    <span class="string">"strict"</span>: <span class="literal">true</span>,                        <span class="comment">// 启用所有严格类型检查选项</span></span><br><span class="line">    <span class="string">"noImplicitAny"</span>: <span class="literal">true</span>,                 <span class="comment">// 在表达式和声明上有隐含的 any类型时报错</span></span><br><span class="line">    <span class="string">"strictNullChecks"</span>: <span class="literal">true</span>,              <span class="comment">// 启用严格的 null 检查</span></span><br><span class="line">    <span class="string">"noImplicitThis"</span>: <span class="literal">true</span>,                <span class="comment">// 当 this 表达式值为 any 类型的时候，生成一个错误</span></span><br><span class="line">    <span class="string">"alwaysStrict"</span>: <span class="literal">true</span>,                  <span class="comment">// 以严格模式检查每个模块，并在每个文件里加入 'use strict'</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 额外的检查 */</span></span><br><span class="line">    <span class="string">"noUnusedLocals"</span>: <span class="literal">true</span>,                <span class="comment">// 有未使用的变量时，抛出错误</span></span><br><span class="line">    <span class="string">"noUnusedParameters"</span>: <span class="literal">true</span>,            <span class="comment">// 有未使用的参数时，抛出错误</span></span><br><span class="line">    <span class="string">"noImplicitReturns"</span>: <span class="literal">true</span>,             <span class="comment">// 并不是所有函数里的代码都有返回值时，抛出错误</span></span><br><span class="line">    <span class="string">"noFallthroughCasesInSwitch"</span>: <span class="literal">true</span>,    <span class="comment">// 报告 switch 语句的 fallthrough 错误。（即，不允许 switch 的 case 语句贯穿）</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 模块解析选项 */</span></span><br><span class="line">    <span class="string">"moduleResolution"</span>: <span class="string">"node"</span>,            <span class="comment">// 选择模块解析策略： 'node' (Node.js) or 'classic' (TypeScript pre-1.6)</span></span><br><span class="line">    <span class="string">"baseUrl"</span>: <span class="string">"./"</span>,                       <span class="comment">// 用于解析非相对模块名称的基目录</span></span><br><span class="line">    <span class="string">"paths"</span>: &#123;&#125;,                           <span class="comment">// 模块名到基于 baseUrl 的路径映射的列表</span></span><br><span class="line">    <span class="string">"rootDirs"</span>: [],                        <span class="comment">// 根文件夹列表，其组合内容表示项目运行时的结构内容</span></span><br><span class="line">    <span class="string">"typeRoots"</span>: [],                       <span class="comment">// 包含类型声明的文件列表</span></span><br><span class="line">    <span class="string">"types"</span>: [],                           <span class="comment">// 需要包含的类型声明文件名列表</span></span><br><span class="line">    <span class="string">"allowSyntheticDefaultImports"</span>: <span class="literal">true</span>,  <span class="comment">// 允许从没有设置默认导出的模块中默认导入。</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* Source Map Options */</span></span><br><span class="line">    <span class="string">"sourceRoot"</span>: <span class="string">"./"</span>,                    <span class="comment">// 指定调试器应该找到 TypeScript 文件而不是源文件的位置</span></span><br><span class="line">    <span class="string">"mapRoot"</span>: <span class="string">"./"</span>,                       <span class="comment">// 指定调试器应该找到映射文件而不是生成文件的位置</span></span><br><span class="line">    <span class="string">"inlineSourceMap"</span>: <span class="literal">true</span>,               <span class="comment">// 生成单个 soucemaps 文件，而不是将 sourcemaps 生成不同的文件</span></span><br><span class="line">    <span class="string">"inlineSources"</span>: <span class="literal">true</span>,                 <span class="comment">// 将代码与 sourcemaps 生成到一个文件中，要求同时设置了 --inlineSourceMap 或 --sourceMap 属性</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 其他选项 */</span></span><br><span class="line">    <span class="string">"experimentalDecorators"</span>: <span class="literal">true</span>,        <span class="comment">// 启用装饰器</span></span><br><span class="line">    <span class="string">"emitDecoratorMetadata"</span>: <span class="literal">true</span>          <span class="comment">// 为装饰器提供元数据的支持</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="4-2-TypeScript-编译"><a href="#4-2-TypeScript-编译" class="headerlink" title="4.2 TypeScript 编译"></a>4.2 TypeScript 编译</h2><blockquote>
<p>运行 <code>tsc -p ./path-to-project-directory</code> 。<code>tsc -w</code>来启用 <code>TypeScript</code>编译器的观测模式，在检测到文件改动之后，它将重新编译</p>
</blockquote>
<p><strong>指定需要编译的文件</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="string">"files"</span>: [</span><br><span class="line">    <span class="string">"./some/file.ts"</span></span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>使用 include 和 exclude 选项来指定需要包含的文件，和排除的文件</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="string">"include"</span>: [</span><br><span class="line">    <span class="string">"./folder"</span></span><br><span class="line">  ],</span><br><span class="line">  <span class="string">"exclude"</span>: [</span><br><span class="line">    <span class="string">"./folder/**/*.spec.ts"</span>,</span><br><span class="line">    <span class="string">"./folder/someSubFolder"</span></span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h1 id="五、一些例子演示"><a href="#五、一些例子演示" class="headerlink" title="五、一些例子演示"></a>五、一些例子演示</h1><h2 id="5-1-定义ajax请求数据接口"><a href="#5-1-定义ajax请求数据接口" class="headerlink" title="5.1 定义ajax请求数据接口"></a>5.1 定义ajax请求数据接口</h2><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Config&#123;</span><br><span class="line">    type:string;</span><br><span class="line">    url:string;</span><br><span class="line">    data?:string;</span><br><span class="line">    dataType:string;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//原生js封装的ajax </span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">ajax</span>(<span class="params">config:Config</span>)</span>&#123;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">var</span> xhr=<span class="keyword">new</span> XMLHttpRequest();</span><br><span class="line"></span><br><span class="line">   xhr.open(config.type,config.url,<span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">   xhr.send(config.data);</span><br><span class="line"></span><br><span class="line">   xhr.onreadystatechange=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span>(xhr.readyState==<span class="number">4</span> &amp;&amp; xhr.status==<span class="number">200</span>)&#123;</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">'chengong'</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span>(config.dataType==<span class="string">'json'</span>)&#123;</span><br><span class="line"></span><br><span class="line">                <span class="built_in">console</span>.log(<span class="built_in">JSON</span>.parse(xhr.responseText));</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                <span class="built_in">console</span>.log(xhr.responseText)</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">ajax(&#123;</span><br><span class="line">    type:<span class="string">'get'</span>,</span><br><span class="line">    data:<span class="string">'name=zhangsan'</span>,</span><br><span class="line">    url:<span class="string">'http://a.itying.com/api/productlist'</span>, <span class="comment">//api</span></span><br><span class="line">    dataType:<span class="string">'json'</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<h2 id="5-2-函数类型接口-对方法约束"><a href="#5-2-函数类型接口-对方法约束" class="headerlink" title="5.2 函数类型接口-对方法约束"></a>5.2 函数类型接口-对方法约束</h2><figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 函数类型接口:对方法传入的参数 以及返回值进行约束   批量约束</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 加密的函数类型接口</span></span><br><span class="line"></span><br><span class="line">interface encrypt&#123;</span><br><span class="line">    (key:string,<span class="attr">value</span>:string):string;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> md5:encrypt=<span class="function"><span class="keyword">function</span>(<span class="params">key:string,value:string</span>):<span class="title">string</span></span>&#123;</span><br><span class="line">        <span class="comment">//模拟操作</span></span><br><span class="line">        <span class="keyword">return</span> key+value;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(md5(<span class="string">'name'</span>,<span class="string">'zhangsan'</span>));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> sha1:encrypt=<span class="function"><span class="keyword">function</span>(<span class="params">key:string,value:string</span>):<span class="title">string</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//模拟操作</span></span><br><span class="line">    <span class="keyword">return</span> key+<span class="string">'----'</span>+value;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(sha1(<span class="string">'name'</span>,<span class="string">'lisi'</span>));</span><br></pre></td></tr></table></figure>
<h2 id="5-3-可索引接口：数组、对象的约束（不常用）"><a href="#5-3-可索引接口：数组、对象的约束（不常用）" class="headerlink" title="5.3 可索引接口：数组、对象的约束（不常用）"></a>5.3 可索引接口：数组、对象的约束（不常用）</h2><h3 id="5-3-1-可索引接口-对数组的约束"><a href="#5-3-1-可索引接口-对数组的约束" class="headerlink" title="5.3.1 可索引接口-对数组的约束"></a>5.3.1 可索引接口-对数组的约束</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface UserArr&#123;</span><br><span class="line">    [index:number]:string</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> arr:UserArr=[<span class="string">'aaa'</span>,<span class="string">'bbb'</span>];</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(arr[<span class="number">0</span>]);</span><br></pre></td></tr></table></figure>
<h3 id="5-3-2-可索引接口-对对象的约束"><a href="#5-3-2-可索引接口-对对象的约束" class="headerlink" title="5.3.2 可索引接口-对对象的约束"></a>5.3.2 可索引接口-对对象的约束</h3><figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface UserObj&#123;</span><br><span class="line">    [index:string]:string</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> arr:UserObj=&#123;<span class="attr">name</span>:<span class="string">'张三'</span>&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="5-3-3-类类型接口-对类的约束"><a href="#5-3-3-类类型接口-对类的约束" class="headerlink" title="5.3.3 类类型接口:对类的约束"></a>5.3.3 类类型接口:对类的约束</h3><ul>
<li>抽象类抽象有点相似    </li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Animal&#123;</span><br><span class="line">    name:string;</span><br><span class="line">    eat(str:string):<span class="keyword">void</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Dog</span> <span class="title">implements</span> <span class="title">Animal</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    name:string;</span><br><span class="line">    <span class="keyword">constructor</span>(name:string)&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">this</span>.name=name;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    eat()&#123;</span><br><span class="line"></span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.name+<span class="string">'吃粮食'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> d=<span class="keyword">new</span> Dog(<span class="string">'小黑'</span>);</span><br><span class="line">d.eat();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="title">implements</span> <span class="title">Animal</span></span>&#123;</span><br><span class="line">    name:string;</span><br><span class="line">    <span class="keyword">constructor</span>(name:string)&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">this</span>.name=name;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    eat(food:string)&#123;</span><br><span class="line"></span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.name+<span class="string">'吃'</span>+food);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> c=<span class="keyword">new</span> Cat(<span class="string">'小花'</span>);</span><br><span class="line">c.eat(<span class="string">'老鼠'</span>);</span><br></pre></td></tr></table></figure>
<h2 id="5-4-接口的扩展"><a href="#5-4-接口的扩展" class="headerlink" title="5.4 接口的扩展"></a>5.4 接口的扩展</h2><blockquote>
<p>接口继承接口 类实现接口</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface Animal&#123;</span><br><span class="line">    eat():<span class="keyword">void</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">interface Person extends Animal&#123;</span><br><span class="line"></span><br><span class="line">    work():<span class="keyword">void</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Programmer</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    public name:string;</span><br><span class="line">    <span class="keyword">constructor</span>(name:string)&#123;</span><br><span class="line">        <span class="keyword">this</span>.name=name;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    coding(code:string)&#123;</span><br><span class="line"></span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.name+code)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Web</span> <span class="keyword">extends</span> <span class="title">Programmer</span> <span class="title">implements</span> <span class="title">Person</span></span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">constructor</span>(name:string)&#123;</span><br><span class="line">       <span class="keyword">super</span>(name)</span><br><span class="line">    &#125;</span><br><span class="line">    eat()&#123;</span><br><span class="line"></span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.name+<span class="string">'喜欢吃馒头'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    work()&#123;</span><br><span class="line"></span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.name+<span class="string">'写代码'</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> w=<span class="keyword">new</span> Web(<span class="string">'小李'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// w.eat();</span></span><br><span class="line"></span><br><span class="line">w.coding(<span class="string">'写ts代码'</span>);</span><br></pre></td></tr></table></figure>
<h2 id="5-5-泛型类接口"><a href="#5-5-泛型类接口" class="headerlink" title="5.5 泛型类接口"></a>5.5 泛型类接口</h2><h3 id="5-5-1-泛型类-泛型方法"><a href="#5-5-1-泛型类-泛型方法" class="headerlink" title="5.5.1 泛型类 泛型方法"></a>5.5.1 泛型类 泛型方法</h3><ul>
<li>泛型：软件工程中，我们不仅要创建一致的定义良好的<code>API</code>，同时也要考虑可重用性。 组件不仅能够支持当前的数据类型，同时也能支持未来的数据类型，这在创建大型系统时为你提供了十分灵活的功能。</li>
<li>在像<code>C#</code>和<code>Java</code>这样的语言中，可以使用泛型来创建可重用的组件，一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。</li>
<li>通俗理解：泛型就是解决类接口方法的复用性、以及对不特定数据类型的支持(类型校验)</li>
</ul>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 只能返回string类型的数据</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData</span>(<span class="params">value:string</span>):<span class="title">string</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> value;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 同时返回 string类型 和number类型  （代码冗余）</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData1</span>(<span class="params">value:string</span>):<span class="title">string</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> value;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData2</span>(<span class="params">value:number</span>):<span class="title">number</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> value;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//同时返回 string类型 和number类型  any可以解决这个问题</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">getData</span>(<span class="params">value:any</span>):<span class="title">any</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">'哈哈哈'</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">getData(<span class="number">123</span>);</span><br><span class="line">getData(<span class="string">'str'</span>);</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">//any放弃了类型检查,传入什么 返回什么。比如:传入number 类型必须返回number类型  传入 string类型必须返回string类型</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//传入的参数类型和返回的参数类型可以不一致</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData</span>(<span class="params">value:any</span>):<span class="title">any</span></span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">'哈哈哈'</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p><code>T</code>表示泛型，具体什么类型是调用这个方法的时候决定的</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// T表示泛型，具体什么类型是调用这个方法的时候决定的</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData</span>&lt;<span class="title">T</span>&gt;(<span class="params">value:T</span>):<span class="title">T</span></span>&#123;</span><br><span class="line">   <span class="keyword">return</span> value;</span><br><span class="line">&#125;</span><br><span class="line">getData&lt;number&gt;(<span class="number">123</span>);</span><br><span class="line"></span><br><span class="line">getData&lt;string&gt;(<span class="string">'1214231'</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">getData&lt;number&gt;(<span class="string">'2112'</span>);       <span class="comment">/*错误的写法*/</span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData</span>&lt;<span class="title">T</span>&gt;(<span class="params">value:T</span>):<span class="title">any</span></span>&#123;</span><br><span class="line">   <span class="keyword">return</span> <span class="string">'2145214214'</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">getData&lt;number&gt;(<span class="number">123</span>);  <span class="comment">//参数必须是number</span></span><br><span class="line"></span><br><span class="line">getData&lt;string&gt;(<span class="string">'这是一个泛型'</span>);</span><br></pre></td></tr></table></figure>
<p><strong>泛型类</strong></p>
<blockquote>
<p>泛型类：比如有个最小堆算法，需要同时支持返回数字和字符串 <code>a  -  z</code>两种类型。  通过类的泛型来实现</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 基本写法 但是不能传入字符串</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MinClass</span></span>&#123;</span><br><span class="line">    public list:number[]=[];</span><br><span class="line">    add(num:number)&#123;</span><br><span class="line">        <span class="keyword">this</span>.list.push(num)</span><br><span class="line">    &#125;</span><br><span class="line">    min():number&#123;</span><br><span class="line">        <span class="keyword">var</span> minNum=<span class="keyword">this</span>.list[<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">var</span> i=<span class="number">0</span>;i&lt;<span class="keyword">this</span>.list.length;i++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(minNum&gt;<span class="keyword">this</span>.list[i])&#123;</span><br><span class="line">                minNum=<span class="keyword">this</span>.list[i];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> minNum;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> m=<span class="keyword">new</span> MinClass();</span><br><span class="line"></span><br><span class="line">m.add(<span class="number">3</span>);</span><br><span class="line">m.add(<span class="number">22</span>);</span><br><span class="line">m.add(<span class="number">23</span>);</span><br><span class="line">m.add(<span class="number">6</span>);</span><br><span class="line"></span><br><span class="line">m.add(<span class="number">7</span>);</span><br><span class="line">alert(m.min());</span><br></pre></td></tr></table></figure>
<p><strong>类的泛型</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 通过泛型改写 可以同时传入number 字符串等</span></span><br><span class="line"><span class="comment">//类的泛型</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MinClas</span>&lt;<span class="title">T</span>&gt;</span>&#123;</span><br><span class="line"></span><br><span class="line">    public list:T[]=[];</span><br><span class="line"></span><br><span class="line">    add(value:T):<span class="keyword">void</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">this</span>.list.push(value);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    min():T&#123;        </span><br><span class="line">        <span class="keyword">var</span> minNum=<span class="keyword">this</span>.list[<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">var</span> i=<span class="number">0</span>;i&lt;<span class="keyword">this</span>.list.length;i++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(minNum&gt;<span class="keyword">this</span>.list[i])&#123;</span><br><span class="line">                minNum=<span class="keyword">this</span>.list[i];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> minNum;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> m1=<span class="keyword">new</span> MinClas&lt;number&gt;();   <span class="comment">/*实例化类 并且制定了类的T代表的类型是number*/</span></span><br><span class="line">m1.add(<span class="number">11</span>);</span><br><span class="line">m1.add(<span class="number">3</span>);</span><br><span class="line">m1.add(<span class="number">2</span>);</span><br><span class="line">alert(m1.min())</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> m2=<span class="keyword">new</span> MinClas&lt;string&gt;();   <span class="comment">/*实例化类 并且制定了类的T代表的类型是string*/</span></span><br><span class="line"></span><br><span class="line">m2.add(<span class="string">'c'</span>);</span><br><span class="line">m2.add(<span class="string">'a'</span>);</span><br><span class="line">m2.add(<span class="string">'v'</span>);</span><br><span class="line">alert(m2.min())</span><br></pre></td></tr></table></figure>
<h3 id="5-5-2-泛型接口"><a href="#5-5-2-泛型接口" class="headerlink" title="5.5.2 泛型接口"></a>5.5.2 泛型接口</h3><p><strong>1. 方式1</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface ConfigFn&#123;</span><br><span class="line"></span><br><span class="line">    &lt;T&gt;(value:T):T;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> getData:ConfigFn=<span class="function"><span class="keyword">function</span>&lt;<span class="title">T</span>&gt;(<span class="params">value:T</span>):<span class="title">T</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> value;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">getData&lt;string&gt;(<span class="string">'张三'</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// getData&lt;string&gt;(1243);  //错误</span></span><br></pre></td></tr></table></figure>
<p><strong>2. 方式2</strong></p>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line">interface ConfigFn&lt;T&gt;&#123;</span><br><span class="line">    (value:T):T;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData</span>&lt;<span class="title">T</span>&gt;(<span class="params">value:T</span>):<span class="title">T</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> value;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> myGetData:ConfigFn&lt;string&gt;=getData;     </span><br><span class="line"></span><br><span class="line"></span><br><span class="line">myGetData(<span class="string">'20'</span>);  <span class="comment">/*正确*/</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// myGetData(20)  //错误</span></span><br></pre></td></tr></table></figure>
<h1 id="六、更多参考"><a href="#六、更多参考" class="headerlink" title="六、更多参考"></a>六、更多参考</h1><ul>
<li><a href="https://www.tslang.cn/docs/handbook/typescript-in-5-minutes.html" target="_blank" rel="noopener">Typescript中文网</a></li>
<li><a href="http://jspang.com/post/typescript.html#toc-a39" target="_blank" rel="noopener">技术胖Typescript视频学习入门</a></li>
</ul>

      </div>
    
  </div>

</article>

<button class="assist-btn2 circle" id="assist_btn2" title="点亮屏幕" style="left: 27px; top: 152px;">
  <i class="iconfont" style="display:inline-block;color:red;width:20px;height:20px;">&#xe61d;</i>
</button>
<button class="assist-btn1 circle" id="assist_btn1" title="关闭屏幕亮度" style="left: 27px; top: 152px;">
  <i class="iconfont toc-title" style="display:inline-block;color:red;width:20px;height:20px;">&#xe61d;</i>
</button>


<script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>	

<script src="https://my.openwrite.cn/js/readmore.js" type="text/javascript"></script>
<script>
  const btw = new BTWPlugin();
  btw.init({
    id: "container",
    blogId: "22699-1592137983091-414",
    name: "前端进阶之旅",
    qrcode: "https://poetries1.gitee.io/img-repo/2020/06/qrcode.jpg",
    keyword: "3a3b3c",
  });
</script>

<script type="text/javascript">

// white theme
var body = {color: "#555", background: "#000"};
var a_tag = {color: "#222"};
var header = { background: "#222"};
var logo_line_i = {background: "#222"};
// var post_code = {background: "#eee", color: "#222"};

function switch_theme() {
 $("body").css(body);
 $("a:not('.links-of-author-item a, .site-state-item a, .site-state-posts a, .feed-link a, .motion-element a, .post-tags a, .show-commit-cls a, #donate_board a')").css(a_tag);
 $(".header, .footer").css(header);
 $(".logo-line-before i, .logo-line-after i").css(logo_line_i);
 //$(".post code").css(post_code);
 $("#idhyt-surprise-ball #idhyt-surprise-ball-animation .drag").css(a_tag);
 $(".post-title-link, .posts-expand .post-meta, .post-comments-count, .disqus-comment-count, .post-category a, .post-nav-next a, .post-nav-item a").css(a_tag);
 
 // $("code").css({color: '#c5c8c6', background: '#1d1f21'});
 //$("#assist_btn1").hide(1500);
}

$(function () {
$("#assist_btn2").css("display","none");
 $("#assist_btn1").click(function() {
     switch_theme();
$("div#toc.toc-article").css({
 "background":"#eaeaea",
 "opacity":1
});
$(".toc-article ol").show();
$("#toc.toc-article .toc-title").css("color","#a98602");
$("#assist_btn1").css("display","none");
$("#assist_btn2").css("display","block");
 });
$("#assist_btn2").click(function() {
$("#assist_btn2").css("display","none");
$("#assist_btn1").css("display","block");
$("body").css("background","url(http://www.miaov.com/static/ie/images/news/bg.png)")
     $(".header, .footer").css("background","url(http://www.miaov.com/static/ie/images/news/bg.png)")
$(".toc-article ol").toggle(1000);
 });
});


//背景随机

var Y, O, E, L, B, C, T, z, N, S, A, I;
!function() {
var e = function() {
for (O.clearRect(0, 0, L, B), T = [{
x: 0,
y: .7 * B + C
}, {
x: 0,
y: .7 * B - C
}]; T[1].x < L + C;) t(T[0], T[1])
}, t = function(e, t) {
O.beginPath(), O.moveTo(e.x, e.y), O.lineTo(t.x, t.y);
var n = t.x + (2 * I() - .25) * C,
 r = a(t.y);
O.lineTo(n, r), O.closePath(), N -= S / -50, O.fillStyle = "#" + (127 * A(N) + 128 << 16 | 127 * A(N + S / 3) + 128 << 8 | 127 * A(N + S / 3 * 2) + 128).toString(16), O.fill(), T[0] = T[1], T[1] = {
 x: n,
 y: r
}
}, a = function n(e) {
var t = e + (2 * I() - 1.1) * C;
return t > B || t < 0 ? n(e) : t
};
Y = document.getElementById("evanyou"), O = Y.getContext("2d"), E = window.devicePixelRatio || 1, L = window.innerWidth, B = window.innerHeight, C = 90, z = Math, N = 0, S = 2 * z.PI, A = z.cos, I = z.random, Y.width = L * E, Y.height = B * E, O.scale(E, E), O.globalAlpha = .6, document.onclick = e, document.ontouchstart = e, e()
}()

   
$("#toc-eye").click(function(){
$("#toc.toc-article").toggle(1000);
});

</script>


   
  <div class="text-center donation">
    <div class="inner-donation">
      <span class="btn-donation">支持一下</span>
      <div class="donation-body">
        <div class="tip text-center">扫一扫，支持poetries</div>
        <ul>
        
          <li class="item">
            
              <span>微信扫一扫</span>
            
            <img src="/images/weixin.jpg" alt="">
          </li>
        
          <li class="item">
            
              <span>支付宝扫一扫</span>
            
            <img src="/images/zhifubao.jpg" alt="">
          </li>
        
        </ul>
      </div>
    </div>
  </div>


   
  <div class="box-prev-next clearfix">
    <a class="show pull-left" href="/2018/12/29/ts-intro-and-use-in-react/">
        <i class="icon icon-angle-left"></i>
    </a>
    <a class="show pull-right" href="/2018/12/31/ts-react-template/">
        <i class="icon icon-angle-right"></i>
    </a>
  </div>




</div>


  <a id="backTop" class="back-top">
    <i class="icon-angle-up"></i>
  </a>




  <div class="modal" id="modal">
  <span id="cover" class="cover hide"></span>
  <div id="modal-dialog" class="modal-dialog hide-dialog">
    <div class="modal-header">
      <span id="close" class="btn-close">关闭</span>
    </div>
    <hr>
    <div class="modal-body">
      <ul class="list-toolbox">
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/archives/"
              rel="noopener noreferrer"
              target="_self"
              >
              博客
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/categories/"
              rel="noopener noreferrer"
              target="_self"
              >
              分类
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/tags/"
              rel="noopener noreferrer"
              target="_self"
              >
              标签
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/search/"
              rel="noopener noreferrer"
              target="_self"
              >
              搜索
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/link/"
              rel="noopener noreferrer"
              target="_self"
              >
              友链
            </a>
          </li>
        
          <li class="item-toolbox">
            <a
              class="CIRCLE"
              href="/about/"
              rel="noopener noreferrer"
              target="_self"
              >
              关于
            </a>
          </li>
        
      </ul>

    </div>
  </div>
</div>



  
      <div class="fexo-comments comments-post">
    

    

    
    

    

    
    

    

<!-- Gitalk评论插件通用代码 -->
<div id="gitalk-container"></div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.css">
<script src="https://cdn.jsdelivr.net/npm/gitalk@1/dist/gitalk.min.js"></script>
<script>
const gitalk = new Gitalk({
  clientID: '5567a2c4abb858009d96',
  clientSecret: 'b9039ec056cf5c2346b3cdb63308a28c163f91e5',
  repo: 'poetries.github.io',
  owner: 'poetries',
  // 在这里设置一下截取前50个字符串, 这是因为 github 对 label 的长度有了要求, 如果超过
  // 50个字符串则会报错.
  // id: location.pathname.split('/').pop().substring(0, 49),
  id: location.pathname,
  admin: ['poetries'],
  // facebook-like distraction free mode
  distractionFreeMode: false
})
gitalk.render('gitalk-container')
</script>
<!-- Gitalk代码结束 -->



  </div>

  

  <script type="text/javascript">
  function loadScript(url, callback) {
    var script = document.createElement('script')
    script.type = 'text/javascript';

    if (script.readyState) { //IE
      script.onreadystatechange = function() {
        if (script.readyState == 'loaded' ||
          script.readyState == 'complete') {
          script.onreadystatechange = null;
          callback();
        }
      };
    } else { //Others
      script.onload = function() {
        callback();
      };
    }

    script.src = url;
    document.getElementsByTagName('head')[0].appendChild(script);
  }

  window.onload = function() {
    loadScript('/js/bundle.js?235683', function() {
      // load success
    });
  }
</script>


  <!-- 页面点击小红心 -->
  <script type="text/javascript" src="/js/clicklove.js"></script>
 
  
</body>
</html>
